Merge branch 'master' into redox_builder
This commit is contained in:
commit
e500fc3171
207 changed files with 4819 additions and 3251 deletions
|
|
@ -70,7 +70,7 @@ for details on how to format and write long error codes.
|
|||
[librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs),
|
||||
[librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs),
|
||||
[librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs),
|
||||
[librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs),
|
||||
[librustc_plugin_impl](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs),
|
||||
[librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs).
|
||||
* Explanations have full markdown support. Use it, especially to highlight
|
||||
code with backticks.
|
||||
|
|
|
|||
36
src/doc/unstable-book/src/language-features/or-patterns.md
Normal file
36
src/doc/unstable-book/src/language-features/or-patterns.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# `or_patterns`
|
||||
|
||||
The tracking issue for this feature is: [#54883]
|
||||
|
||||
[#54883]: https://github.com/rust-lang/rust/issues/54883
|
||||
|
||||
------------------------
|
||||
|
||||
The `or_pattern` language feature allows `|` to be arbitrarily nested within
|
||||
a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.
|
||||
|
||||
## Examples
|
||||
|
||||
```rust,ignore
|
||||
#![feature(or_patterns)]
|
||||
|
||||
pub enum Foo {
|
||||
Bar,
|
||||
Baz,
|
||||
Quux,
|
||||
}
|
||||
|
||||
pub fn example(maybe_foo: Option<Foo>) {
|
||||
match maybe_foo {
|
||||
Some(Foo::Bar | Foo::Baz) => {
|
||||
println!("The value contained `Bar` or `Baz`");
|
||||
}
|
||||
Some(_) => {
|
||||
println!("The value did not contain `Bar` or `Baz`");
|
||||
}
|
||||
None => {
|
||||
println!("The value was `None`");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -18,7 +18,7 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
|||
A plugin is a dynamic library crate with a designated *registrar* function that
|
||||
registers extensions with `rustc`. Other crates can load these extensions using
|
||||
the crate attribute `#![plugin(...)]`. See the
|
||||
`rustc_plugin` documentation for more about the
|
||||
`rustc_driver::plugin` documentation for more about the
|
||||
mechanics of defining and loading a plugin.
|
||||
|
||||
If present, arguments passed as `#![plugin(foo(... args ...))]` are not
|
||||
|
|
@ -54,13 +54,13 @@ that implements Roman numeral integer literals.
|
|||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
extern crate rustc_driver;
|
||||
|
||||
use syntax::parse::token::{self, Token};
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
|
||||
use syntax_pos::Span;
|
||||
use rustc_plugin::Registry;
|
||||
use rustc_driver::plugin::Registry;
|
||||
|
||||
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||
-> Box<dyn MacResult + 'static> {
|
||||
|
|
@ -180,11 +180,11 @@ extern crate syntax;
|
|||
// Load rustc as a plugin to get macros
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
extern crate rustc_driver;
|
||||
|
||||
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
|
||||
EarlyLintPassObject, LintArray};
|
||||
use rustc_plugin::Registry;
|
||||
use rustc_driver::plugin::Registry;
|
||||
use syntax::ast;
|
||||
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
|
|
|||
|
|
@ -91,8 +91,10 @@ use core::ops::{
|
|||
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
|
||||
};
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::slice;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use crate::alloc::{self, Global, Alloc};
|
||||
use crate::vec::Vec;
|
||||
use crate::raw_vec::RawVec;
|
||||
use crate::str::from_boxed_utf8_unchecked;
|
||||
|
|
@ -121,6 +123,34 @@ impl<T> Box<T> {
|
|||
box x
|
||||
}
|
||||
|
||||
/// Constructs a new box with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut five = Box::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// five.as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
|
||||
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
|
||||
let ptr = unsafe {
|
||||
Global.alloc(layout)
|
||||
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
|
||||
};
|
||||
Box(ptr.cast().into())
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `x` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
|
|
@ -130,6 +160,111 @@ impl<T> Box<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Box<[T]> {
|
||||
/// Constructs a new boxed slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// values[0].as_mut_ptr().write(1);
|
||||
/// values[1].as_mut_ptr().write(2);
|
||||
/// values[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
|
||||
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
|
||||
let ptr = unsafe { alloc::alloc(layout) };
|
||||
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
|
||||
Box(Unique::from(slice))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Box<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut five = Box::<u32>::new_uninit();
|
||||
///
|
||||
/// let five: Box<u32> = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// five.as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Box<T> {
|
||||
Box(Box::into_unique(self).cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Box<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the values
|
||||
/// really are in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// values[0].as_mut_ptr().write(1);
|
||||
/// values[1].as_mut_ptr().write(2);
|
||||
/// values[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Box<[T]> {
|
||||
Box(Unique::new_unchecked(Box::into_raw(self) as _))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Box<T> {
|
||||
/// Constructs a box from a raw pointer.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1199,6 +1199,31 @@ impl<T> VecDeque<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Removes the last element from the `VecDeque` and returns it, or `None` if
|
||||
/// it is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// assert_eq!(buf.pop_back(), None);
|
||||
/// buf.push_back(1);
|
||||
/// buf.push_back(3);
|
||||
/// assert_eq!(buf.pop_back(), Some(3));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn pop_back(&mut self) -> Option<T> {
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
self.head = self.wrap_sub(self.head, 1);
|
||||
let head = self.head;
|
||||
unsafe { Some(self.buffer_read(head)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepends an element to the `VecDeque`.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1243,71 +1268,11 @@ impl<T> VecDeque<T> {
|
|||
unsafe { self.buffer_write(head, value) }
|
||||
}
|
||||
|
||||
/// Removes the last element from the `VecDeque` and returns it, or `None` if
|
||||
/// it is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// assert_eq!(buf.pop_back(), None);
|
||||
/// buf.push_back(1);
|
||||
/// buf.push_back(3);
|
||||
/// assert_eq!(buf.pop_back(), Some(3));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn pop_back(&mut self) -> Option<T> {
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
self.head = self.wrap_sub(self.head, 1);
|
||||
let head = self.head;
|
||||
unsafe { Some(self.buffer_read(head)) }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_contiguous(&self) -> bool {
|
||||
self.tail <= self.head
|
||||
}
|
||||
|
||||
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
|
||||
/// last element.
|
||||
///
|
||||
/// This does not preserve ordering, but is O(1).
|
||||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// assert_eq!(buf.swap_remove_back(0), None);
|
||||
/// buf.push_back(1);
|
||||
/// buf.push_back(2);
|
||||
/// buf.push_back(3);
|
||||
/// assert_eq!(buf, [1, 2, 3]);
|
||||
///
|
||||
/// assert_eq!(buf.swap_remove_back(0), Some(1));
|
||||
/// assert_eq!(buf, [3, 2]);
|
||||
/// ```
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
|
||||
let length = self.len();
|
||||
if length > 0 && index < length - 1 {
|
||||
self.swap(index, length - 1);
|
||||
} else if index >= length {
|
||||
return None;
|
||||
}
|
||||
self.pop_back()
|
||||
}
|
||||
|
||||
/// Removes an element from anywhere in the `VecDeque` and returns it,
|
||||
/// replacing it with the first element.
|
||||
///
|
||||
|
|
@ -1343,6 +1308,41 @@ impl<T> VecDeque<T> {
|
|||
self.pop_front()
|
||||
}
|
||||
|
||||
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
|
||||
/// last element.
|
||||
///
|
||||
/// This does not preserve ordering, but is O(1).
|
||||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// assert_eq!(buf.swap_remove_back(0), None);
|
||||
/// buf.push_back(1);
|
||||
/// buf.push_back(2);
|
||||
/// buf.push_back(3);
|
||||
/// assert_eq!(buf, [1, 2, 3]);
|
||||
///
|
||||
/// assert_eq!(buf.swap_remove_back(0), Some(1));
|
||||
/// assert_eq!(buf, [3, 2]);
|
||||
/// ```
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
|
||||
let length = self.len();
|
||||
if length > 0 && index < length - 1 {
|
||||
self.swap(index, length - 1);
|
||||
} else if index >= length {
|
||||
return None;
|
||||
}
|
||||
self.pop_back()
|
||||
}
|
||||
|
||||
/// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices
|
||||
/// greater than or equal to `index` towards the back.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -327,6 +327,37 @@ impl<T> Rc<T> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc` with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut five = Rc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
|
||||
unsafe {
|
||||
Rc::from_ptr(Rc::allocate_for_layout(
|
||||
Layout::new::<T>(),
|
||||
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `value` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
|
|
@ -377,6 +408,118 @@ impl<T> Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<[T]> {
|
||||
/// Constructs a new reference-counted slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
|
||||
unsafe {
|
||||
Rc::from_ptr(Rc::allocate_for_slice(len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Rc<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut five = Rc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Rc<T> {
|
||||
Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Rc<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Rc<[T]> {
|
||||
Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Consumes the `Rc`, returning the wrapped pointer.
|
||||
///
|
||||
|
|
@ -560,13 +703,46 @@ impl<T: ?Sized> Rc<T> {
|
|||
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
||||
if Rc::is_unique(this) {
|
||||
unsafe {
|
||||
Some(&mut this.ptr.as_mut().value)
|
||||
Some(Rc::get_mut_unchecked(this))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner value,
|
||||
/// without any check.
|
||||
///
|
||||
/// See also [`get_mut`], which is safe and does appropriate checks.
|
||||
///
|
||||
/// [`get_mut`]: struct.Rc.html#method.get_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced
|
||||
/// for the duration of the returned borrow.
|
||||
/// This is trivially the case if no such pointers exist,
|
||||
/// for example immediately after `Rc::new`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut x = Rc::new(String::new());
|
||||
/// unsafe {
|
||||
/// Rc::get_mut_unchecked(&mut x).push_str("foo")
|
||||
/// }
|
||||
/// assert_eq!(*x, "foo");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
&mut this.ptr.as_mut().value
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "ptr_eq", since = "1.17.0")]
|
||||
/// Returns `true` if the two `Rc`s point to the same value (not
|
||||
|
|
@ -704,11 +880,11 @@ impl Rc<dyn Any> {
|
|||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Allocates an `RcBox<T>` with sufficient space for
|
||||
/// an unsized value where the value has the layout provided.
|
||||
/// a possibly-unsized value where the value has the layout provided.
|
||||
///
|
||||
/// The function `mem_to_rcbox` is called with the data pointer
|
||||
/// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
|
||||
unsafe fn allocate_for_unsized(
|
||||
unsafe fn allocate_for_layout(
|
||||
value_layout: Layout,
|
||||
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>
|
||||
) -> *mut RcBox<T> {
|
||||
|
|
@ -737,7 +913,7 @@ impl<T: ?Sized> Rc<T> {
|
|||
/// Allocates an `RcBox<T>` with sufficient space for an unsized value
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
|
||||
// Allocate for the `RcBox<T>` using the given value.
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
|
||||
)
|
||||
|
|
@ -768,7 +944,7 @@ impl<T: ?Sized> Rc<T> {
|
|||
impl<T> Rc<[T]> {
|
||||
/// Allocates an `RcBox<[T]>` with the given length.
|
||||
unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::array::<T>(len).unwrap(),
|
||||
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -107,10 +107,6 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
|||
/// // a, b, and foo are all Arcs that point to the same memory location
|
||||
/// ```
|
||||
///
|
||||
/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly
|
||||
/// the meaning of the code. In the example above, this syntax makes it easier to see that
|
||||
/// this code is creating a new reference rather than copying the whole content of foo.
|
||||
///
|
||||
/// ## `Deref` behavior
|
||||
///
|
||||
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
|
||||
|
|
@ -311,6 +307,37 @@ impl<T> Arc<T> {
|
|||
Self::from_inner(Box::into_raw_non_null(x))
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc` with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut five = Arc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
|
||||
unsafe {
|
||||
Arc::from_ptr(Arc::allocate_for_layout(
|
||||
Layout::new::<T>(),
|
||||
|mem| mem as *mut ArcInner<mem::MaybeUninit<T>>,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Arc<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `data` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
|
|
@ -361,6 +388,118 @@ impl<T> Arc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<[T]> {
|
||||
/// Constructs a new reference-counted slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
|
||||
unsafe {
|
||||
Arc::from_ptr(Arc::allocate_for_slice(len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Arc<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut five = Arc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Arc<T> {
|
||||
Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Arc<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Arc<[T]> {
|
||||
Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Consumes the `Arc`, returning the wrapped pointer.
|
||||
///
|
||||
|
|
@ -593,11 +732,11 @@ impl<T: ?Sized> Arc<T> {
|
|||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Allocates an `ArcInner<T>` with sufficient space for
|
||||
/// an unsized value where the value has the layout provided.
|
||||
/// a possibly-unsized value where the value has the layout provided.
|
||||
///
|
||||
/// The function `mem_to_arcinner` is called with the data pointer
|
||||
/// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
|
||||
unsafe fn allocate_for_unsized(
|
||||
unsafe fn allocate_for_layout(
|
||||
value_layout: Layout,
|
||||
mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>
|
||||
) -> *mut ArcInner<T> {
|
||||
|
|
@ -625,7 +764,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
/// Allocates an `ArcInner<T>` with sufficient space for an unsized value.
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
|
||||
// Allocate for the `ArcInner<T>` using the given value.
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>,
|
||||
)
|
||||
|
|
@ -656,7 +795,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
impl<T> Arc<[T]> {
|
||||
/// Allocates an `ArcInner<[T]>` with the given length.
|
||||
unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::array::<T>(len).unwrap(),
|
||||
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>,
|
||||
)
|
||||
|
|
@ -945,13 +1084,46 @@ impl<T: ?Sized> Arc<T> {
|
|||
// the Arc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
unsafe {
|
||||
Some(&mut this.ptr.as_mut().data)
|
||||
Some(Arc::get_mut_unchecked(this))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner value,
|
||||
/// without any check.
|
||||
///
|
||||
/// See also [`get_mut`], which is safe and does appropriate checks.
|
||||
///
|
||||
/// [`get_mut`]: struct.Arc.html#method.get_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Any other `Arc` or [`Weak`] pointers to the same value must not be dereferenced
|
||||
/// for the duration of the returned borrow.
|
||||
/// This is trivially the case if no such pointers exist,
|
||||
/// for example immediately after `Arc::new`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut x = Arc::new(String::new());
|
||||
/// unsafe {
|
||||
/// Arc::get_mut_unchecked(&mut x).push_str("foo")
|
||||
/// }
|
||||
/// assert_eq!(*x, "foo");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
&mut this.ptr.as_mut().data
|
||||
}
|
||||
|
||||
/// Determine whether this is the unique reference (including weak refs) to
|
||||
/// the underlying data.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -122,6 +122,14 @@ impl<T: ?Sized> Unique<T> {
|
|||
pub unsafe fn as_mut(&mut self) -> &mut T {
|
||||
&mut *self.as_ptr()
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
#[inline]
|
||||
pub const fn cast<U>(self) -> Unique<U> {
|
||||
unsafe {
|
||||
Unique::new_unchecked(self.as_ptr() as *mut U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "ptr_internals", issue = "0")]
|
||||
|
|
|
|||
|
|
@ -468,6 +468,14 @@ pub enum ProcMacro {
|
|||
}
|
||||
|
||||
impl ProcMacro {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
ProcMacro::CustomDerive { trait_name, .. } => trait_name,
|
||||
ProcMacro::Attr { name, .. } => name,
|
||||
ProcMacro::Bang { name, ..} => name
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn custom_derive(
|
||||
trait_name: &'static str,
|
||||
attributes: &'static [&'static str],
|
||||
|
|
|
|||
|
|
@ -140,6 +140,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
let branches: Vec<_> = pats.iter().map(|p| self.pat(p, pred)).collect();
|
||||
self.add_ast_node(pat.hir_id.local_id, &branches)
|
||||
}
|
||||
|
||||
PatKind::Slice(ref pre, ref vec, ref post) => {
|
||||
let pre_exit = self.pats_all(pre.iter(), pred);
|
||||
let vec_exit = self.pats_all(vec.iter(), pre_exit);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::ty::{self, TyCtxt};
|
||||
use crate::hir::map::definitions::FIRST_FREE_DEF_INDEX;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
|
|
@ -102,31 +101,6 @@ newtype_index! {
|
|||
}
|
||||
}
|
||||
|
||||
impl DefIndex {
|
||||
// Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
|
||||
// function maps the index of the macro within the crate (which is also the
|
||||
// index of the macro in the CrateMetadata::proc_macros array) to the
|
||||
// corresponding DefIndex.
|
||||
pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex {
|
||||
// DefIndex for proc macros start from FIRST_FREE_DEF_INDEX,
|
||||
// because the first FIRST_FREE_DEF_INDEX indexes are reserved
|
||||
// for internal use.
|
||||
let def_index = DefIndex::from(
|
||||
proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX)
|
||||
.expect("integer overflow adding `proc_macro_index`"));
|
||||
assert!(def_index != CRATE_DEF_INDEX);
|
||||
def_index
|
||||
}
|
||||
|
||||
// This function is the reverse of from_proc_macro_index() above.
|
||||
pub fn to_proc_macro_index(self: DefIndex) -> usize {
|
||||
self.index().checked_sub(FIRST_FREE_DEF_INDEX)
|
||||
.unwrap_or_else(|| {
|
||||
bug!("using local index {:?} as proc-macro index", self)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_serialize::UseSpecializedEncodable for DefIndex {}
|
||||
impl rustc_serialize::UseSpecializedDecodable for DefIndex {}
|
||||
|
||||
|
|
|
|||
|
|
@ -433,6 +433,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
|
|||
LifetimeName::Static |
|
||||
LifetimeName::Error |
|
||||
LifetimeName::Implicit |
|
||||
LifetimeName::ImplicitObjectLifetimeDefault |
|
||||
LifetimeName::Underscore => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -709,6 +710,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
|||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Or(ref pats) => walk_list!(visitor, visit_pat, pats),
|
||||
PatKind::Tuple(ref tuple_elements, _) => {
|
||||
walk_list!(visitor, visit_pat, tuple_elements);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ use syntax::symbol::{kw, sym, Symbol};
|
|||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::parse::token::{self, Token};
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use syntax_pos::Span;
|
||||
|
||||
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ enum ParenthesizedGenericArgs {
|
|||
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
|
||||
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
|
||||
/// everything into HIR lowering.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum AnonymousLifetimeMode {
|
||||
/// For **Modern** cases, create a new anonymous region parameter
|
||||
/// and reference that.
|
||||
|
|
@ -715,10 +715,16 @@ impl<'a> LoweringContext<'a> {
|
|||
anonymous_lifetime_mode: AnonymousLifetimeMode,
|
||||
op: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
debug!(
|
||||
"with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
|
||||
anonymous_lifetime_mode,
|
||||
);
|
||||
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
|
||||
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
|
||||
let result = op(self);
|
||||
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
|
||||
debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
|
||||
old_anonymous_lifetime_mode);
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -1033,13 +1039,14 @@ impl<'a> LoweringContext<'a> {
|
|||
/// ```
|
||||
///
|
||||
/// returns a `hir::TypeBinding` representing `Item`.
|
||||
fn lower_assoc_ty_constraint(&mut self,
|
||||
c: &AssocTyConstraint,
|
||||
itctx: ImplTraitContext<'_>)
|
||||
-> hir::TypeBinding {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
|
||||
fn lower_assoc_ty_constraint(
|
||||
&mut self,
|
||||
constraint: &AssocTyConstraint,
|
||||
itctx: ImplTraitContext<'_>,
|
||||
) -> hir::TypeBinding {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
|
||||
|
||||
let kind = match c.kind {
|
||||
let kind = match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality {
|
||||
ty: self.lower_ty(ty, itctx)
|
||||
},
|
||||
|
|
@ -1094,7 +1101,7 @@ impl<'a> LoweringContext<'a> {
|
|||
impl_trait_node_id,
|
||||
DefPathData::ImplTrait,
|
||||
ExpnId::root(),
|
||||
DUMMY_SP
|
||||
constraint.span,
|
||||
);
|
||||
|
||||
self.with_dyn_type_scope(false, |this| {
|
||||
|
|
@ -1102,7 +1109,7 @@ impl<'a> LoweringContext<'a> {
|
|||
&Ty {
|
||||
id: this.sess.next_node_id(),
|
||||
node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
|
||||
span: DUMMY_SP,
|
||||
span: constraint.span,
|
||||
},
|
||||
itctx,
|
||||
);
|
||||
|
|
@ -1124,10 +1131,10 @@ impl<'a> LoweringContext<'a> {
|
|||
};
|
||||
|
||||
hir::TypeBinding {
|
||||
hir_id: self.lower_node_id(c.id),
|
||||
ident: c.ident,
|
||||
hir_id: self.lower_node_id(constraint.id),
|
||||
ident: constraint.ident,
|
||||
kind,
|
||||
span: c.span,
|
||||
span: constraint.span,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1355,6 +1362,13 @@ impl<'a> LoweringContext<'a> {
|
|||
opaque_ty_node_id: NodeId,
|
||||
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
|
||||
) -> hir::TyKind {
|
||||
debug!(
|
||||
"lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
|
||||
fn_def_id,
|
||||
opaque_ty_node_id,
|
||||
span,
|
||||
);
|
||||
|
||||
// Make sure we know that some funky desugaring has been going on here.
|
||||
// This is a first: there is code in other places like for loop
|
||||
// desugaring that explicitly states that we don't want to track that.
|
||||
|
|
@ -1382,6 +1396,14 @@ impl<'a> LoweringContext<'a> {
|
|||
&hir_bounds,
|
||||
);
|
||||
|
||||
debug!(
|
||||
"lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
|
||||
);
|
||||
|
||||
debug!(
|
||||
"lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
|
||||
);
|
||||
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: hir::Generics {
|
||||
|
|
@ -1397,7 +1419,7 @@ impl<'a> LoweringContext<'a> {
|
|||
origin: hir::OpaqueTyOrigin::FnReturn,
|
||||
};
|
||||
|
||||
trace!("exist ty from impl trait def-index: {:#?}", opaque_ty_def_index);
|
||||
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
|
||||
let opaque_ty_id = lctx.generate_opaque_type(
|
||||
opaque_ty_node_id,
|
||||
opaque_ty_item,
|
||||
|
|
@ -1445,6 +1467,13 @@ impl<'a> LoweringContext<'a> {
|
|||
parent_index: DefIndex,
|
||||
bounds: &hir::GenericBounds,
|
||||
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
|
||||
debug!(
|
||||
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
|
||||
parent_index={:?}, \
|
||||
bounds={:#?})",
|
||||
opaque_ty_id, parent_index, bounds,
|
||||
);
|
||||
|
||||
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
|
||||
// appear in the bounds, excluding lifetimes that are created within the bounds.
|
||||
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
|
||||
|
|
@ -1532,6 +1561,11 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
hir::LifetimeName::Param(_) => lifetime.name,
|
||||
|
||||
// Refers to some other lifetime that is "in
|
||||
// scope" within the type.
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
|
||||
|
||||
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
|
||||
};
|
||||
|
||||
|
|
@ -2182,6 +2216,14 @@ impl<'a> LoweringContext<'a> {
|
|||
fn_def_id: DefId,
|
||||
opaque_ty_node_id: NodeId,
|
||||
) -> hir::FunctionRetTy {
|
||||
debug!(
|
||||
"lower_async_fn_ret_ty(\
|
||||
output={:?}, \
|
||||
fn_def_id={:?}, \
|
||||
opaque_ty_node_id={:?})",
|
||||
output, fn_def_id, opaque_ty_node_id,
|
||||
);
|
||||
|
||||
let span = output.span();
|
||||
|
||||
let opaque_ty_span = self.mark_span_with_reason(
|
||||
|
|
@ -2264,6 +2306,8 @@ impl<'a> LoweringContext<'a> {
|
|||
),
|
||||
);
|
||||
|
||||
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
|
||||
|
||||
// Calculate all the lifetimes that should be captured
|
||||
// by the opaque type. This should include all in-scope
|
||||
// lifetime parameters, including those defined in-band.
|
||||
|
|
@ -2512,6 +2556,12 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::LifetimeName::Implicit
|
||||
| hir::LifetimeName::Underscore
|
||||
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
span_bug!(
|
||||
param.ident.span,
|
||||
"object-lifetime-default should not occur here",
|
||||
);
|
||||
}
|
||||
hir::LifetimeName::Error => ParamName::Error,
|
||||
};
|
||||
|
||||
|
|
@ -2524,15 +2574,6 @@ impl<'a> LoweringContext<'a> {
|
|||
(param_name, kind)
|
||||
}
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
// Don't expose `Self` (recovered "keyword used as ident" parse error).
|
||||
// `rustc::ty` expects `Self` to be only used for a trait's `Self`.
|
||||
// Instead, use `gensym("Self")` to create a distinct name that looks the same.
|
||||
let ident = if param.ident.name == kw::SelfUpper {
|
||||
param.ident.gensym()
|
||||
} else {
|
||||
param.ident
|
||||
};
|
||||
|
||||
let add_bounds = add_bounds.get(¶m.id).map_or(&[][..], |x| &x);
|
||||
if !add_bounds.is_empty() {
|
||||
let params = self.lower_param_bounds(add_bounds, itctx.reborrow()).into_iter();
|
||||
|
|
@ -2551,7 +2592,7 @@ impl<'a> LoweringContext<'a> {
|
|||
.next(),
|
||||
};
|
||||
|
||||
(hir::ParamName::Plain(ident), kind)
|
||||
(hir::ParamName::Plain(param.ident), kind)
|
||||
}
|
||||
GenericParamKind::Const { ref ty } => {
|
||||
(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const {
|
||||
|
|
@ -2669,6 +2710,9 @@ impl<'a> LoweringContext<'a> {
|
|||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
hir::PatKind::TupleStruct(qpath, pats, ddpos)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
hir::PatKind::Or(pats.iter().map(|x| self.lower_pat(x)).collect())
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
|
|
@ -3261,7 +3305,13 @@ impl<'a> LoweringContext<'a> {
|
|||
AnonymousLifetimeMode::PassThrough => {}
|
||||
}
|
||||
|
||||
self.new_implicit_lifetime(span)
|
||||
let r = hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
|
||||
};
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
r
|
||||
}
|
||||
|
||||
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl<'a> DefCollector<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
pub fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,10 +411,6 @@ impl Definitions {
|
|||
}
|
||||
|
||||
/// Adds a root definition (no parent) and a few other reserved definitions.
|
||||
///
|
||||
/// After the initial definitions are created the first `FIRST_FREE_DEF_INDEX` indexes
|
||||
/// are taken, so the "user" indexes will be allocated starting with `FIRST_FREE_DEF_INDEX`
|
||||
/// in ascending order.
|
||||
pub fn create_root_def(&mut self,
|
||||
crate_name: &str,
|
||||
crate_disambiguator: CrateDisambiguator)
|
||||
|
|
@ -589,19 +585,6 @@ impl DefPathData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Evaluates to the number of tokens passed to it.
|
||||
///
|
||||
/// Logarithmic counting: every one or two recursive expansions, the number of
|
||||
/// tokens to count is divided by two, instead of being reduced by one.
|
||||
/// Therefore, the recursion depth is the binary logarithm of the number of
|
||||
/// tokens to count, and the expanded tree is likewise very small.
|
||||
macro_rules! count {
|
||||
() => (0usize);
|
||||
($one:tt) => (1usize);
|
||||
($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
|
||||
($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
|
||||
}
|
||||
|
||||
// We define the GlobalMetaDataKind enum with this macro because we want to
|
||||
// make sure that we exhaustively iterate over all variants when registering
|
||||
// the corresponding DefIndices in the DefTable.
|
||||
|
|
@ -614,8 +597,6 @@ macro_rules! define_global_metadata_kind {
|
|||
$($variant),*
|
||||
}
|
||||
|
||||
pub const FIRST_FREE_DEF_INDEX: usize = 1 + count!($($variant)*);
|
||||
|
||||
impl GlobalMetaDataKind {
|
||||
fn allocate_def_indices(definitions: &mut Definitions) {
|
||||
$({
|
||||
|
|
|
|||
|
|
@ -221,6 +221,19 @@ pub enum LifetimeName {
|
|||
/// User wrote nothing (e.g., the lifetime in `&u32`).
|
||||
Implicit,
|
||||
|
||||
/// Implicit lifetime in a context like `dyn Foo`. This is
|
||||
/// distinguished from implicit lifetimes elsewhere because the
|
||||
/// lifetime that they default to must appear elsewhere within the
|
||||
/// enclosing type. This means that, in an `impl Trait` context, we
|
||||
/// don't have to create a parameter for them. That is, `impl
|
||||
/// Trait<Item = &u32>` expands to an opaque type like `type
|
||||
/// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item =
|
||||
/// dyn Bar>` expands to `type Foo = impl Trait<Item = dyn Bar +
|
||||
/// 'static>`. The latter uses `ImplicitObjectLifetimeDefault` so
|
||||
/// that surrounding code knows not to create a lifetime
|
||||
/// parameter.
|
||||
ImplicitObjectLifetimeDefault,
|
||||
|
||||
/// Indicates an error during lowering (usually `'_` in wrong place)
|
||||
/// that was already reported.
|
||||
Error,
|
||||
|
|
@ -235,7 +248,9 @@ pub enum LifetimeName {
|
|||
impl LifetimeName {
|
||||
pub fn ident(&self) -> Ident {
|
||||
match *self {
|
||||
LifetimeName::Implicit | LifetimeName::Error => Ident::invalid(),
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Implicit
|
||||
| LifetimeName::Error => Ident::invalid(),
|
||||
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
|
||||
LifetimeName::Param(param_name) => param_name.ident(),
|
||||
|
|
@ -244,7 +259,9 @@ impl LifetimeName {
|
|||
|
||||
pub fn is_elided(&self) -> bool {
|
||||
match self {
|
||||
LifetimeName::Implicit | LifetimeName::Underscore => true,
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Implicit
|
||||
| LifetimeName::Underscore => true,
|
||||
|
||||
// It might seem surprising that `Fresh(_)` counts as
|
||||
// *not* elided -- but this is because, as far as the code
|
||||
|
|
@ -881,6 +898,7 @@ impl Pat {
|
|||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||
s.iter().all(|p| p.walk_(it))
|
||||
}
|
||||
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
|
||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||
s.walk_(it)
|
||||
}
|
||||
|
|
@ -975,6 +993,10 @@ pub enum PatKind {
|
|||
/// `0 <= position <= subpats.len()`
|
||||
TupleStruct(QPath, HirVec<P<Pat>>, Option<usize>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
Or(HirVec<P<Pat>>),
|
||||
|
||||
/// A path pattern for an unit struct/variant or a (maybe-associated) constant.
|
||||
Path(QPath),
|
||||
|
||||
|
|
|
|||
|
|
@ -1687,6 +1687,9 @@ impl<'a> State<'a> {
|
|||
self.s.space();
|
||||
self.s.word("}");
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(&p));
|
||||
}
|
||||
PatKind::Tuple(ref elts, ddpos) => {
|
||||
self.popen();
|
||||
if let Some(ddpos) = ddpos {
|
||||
|
|
|
|||
|
|
@ -1329,7 +1329,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let generics = self.tcx.generics_of(did);
|
||||
// Account for the case where `did` corresponds to `Self`, which doesn't have
|
||||
// the expected type argument.
|
||||
if !param.is_self() {
|
||||
if !(generics.has_self && param.index == 0) {
|
||||
let type_param = generics.type_param(param, self.tcx);
|
||||
let hir = &self.tcx.hir();
|
||||
hir.as_local_hir_id(type_param.def_id).map(|id| {
|
||||
|
|
@ -1337,7 +1337,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
|
||||
// instead we suggest `T: 'a + 'b` in that case.
|
||||
let mut has_bounds = false;
|
||||
if let Node::GenericParam(ref param) = hir.get(id) {
|
||||
if let Node::GenericParam(param) = hir.get(id) {
|
||||
has_bounds = !param.bounds.is_empty();
|
||||
}
|
||||
let sp = hir.span(id);
|
||||
|
|
|
|||
|
|
@ -127,8 +127,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
|
||||
debug!(
|
||||
"instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
|
||||
param_env={:?})",
|
||||
value, parent_def_id, body_id, param_env,
|
||||
param_env={:?}, value_span={:?})",
|
||||
value, parent_def_id, body_id, param_env, value_span,
|
||||
);
|
||||
let mut instantiator = Instantiator {
|
||||
infcx: self,
|
||||
|
|
@ -1108,9 +1108,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
// Use the same type variable if the exact same opaque type appears more
|
||||
// than once in the return type (e.g., if it's passed to a type alias).
|
||||
if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
|
||||
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
|
||||
return opaque_defn.concrete_ty;
|
||||
}
|
||||
let span = tcx.def_span(def_id);
|
||||
debug!("fold_opaque_ty {:?} {:?}", self.value_span, span);
|
||||
let ty_var = infcx
|
||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
||||
|
||||
|
|
|
|||
|
|
@ -1290,6 +1290,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
for pat in pats {
|
||||
self.cat_pattern_(cmt.clone(), &pat, op)?;
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Binding(.., Some(ref subpat)) => {
|
||||
self.cat_pattern_(cmt, &subpat, op)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
//! used between functions, and they operate in a purely top-down
|
||||
//! way. Therefore, we break lifetime name resolution into a separate pass.
|
||||
|
||||
// ignore-tidy-filelength
|
||||
|
||||
use crate::hir::def::{Res, DefKind};
|
||||
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use crate::hir::map::Map;
|
||||
|
|
@ -556,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
||||
debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty);
|
||||
debug!("visit_ty: ty.node={:?}", ty.node);
|
||||
match ty.node {
|
||||
hir::TyKind::BareFn(ref c) => {
|
||||
let next_early_index = self.next_early_index();
|
||||
|
|
@ -585,11 +588,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
self.is_in_fn_syntax = was_in_fn_syntax;
|
||||
}
|
||||
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
|
||||
debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime);
|
||||
for bound in bounds {
|
||||
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
||||
}
|
||||
match lifetime.name {
|
||||
LifetimeName::Implicit => {
|
||||
// For types like `dyn Foo`, we should
|
||||
// generate a special form of elided.
|
||||
span_bug!(
|
||||
ty.span,
|
||||
"object-lifetime-default expected, not implict",
|
||||
);
|
||||
}
|
||||
LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
// If the user does not write *anything*, we
|
||||
// use the object lifetime defaulting
|
||||
// rules. So e.g., `Box<dyn Debug>` becomes
|
||||
|
|
@ -897,6 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref);
|
||||
if lifetime_ref.is_elided() {
|
||||
self.resolve_elided_lifetimes(vec![lifetime_ref]);
|
||||
return;
|
||||
|
|
@ -1911,6 +1924,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_segment_args(&mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs) {
|
||||
debug!(
|
||||
"visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
|
||||
res,
|
||||
depth,
|
||||
generic_args,
|
||||
);
|
||||
|
||||
if generic_args.parenthesized {
|
||||
let was_in_fn_syntax = self.is_in_fn_syntax;
|
||||
self.is_in_fn_syntax = true;
|
||||
|
|
@ -1964,6 +1984,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
debug!("visit_segment_args: type_def_id={:?}", type_def_id);
|
||||
|
||||
// Compute a vector of defaults, one for each type parameter,
|
||||
// per the rules given in RFCs 599 and 1156. Example:
|
||||
//
|
||||
// ```rust
|
||||
// struct Foo<'a, T: 'a, U> { }
|
||||
// ```
|
||||
//
|
||||
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
|
||||
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
|
||||
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
|
||||
// such bound).
|
||||
//
|
||||
// Therefore, we would compute `object_lifetime_defaults` to a
|
||||
// vector like `['x, 'static]`. Note that the vector only
|
||||
// includes type parameters.
|
||||
let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
|
||||
let in_body = {
|
||||
let mut scope = self.scope;
|
||||
|
|
@ -2003,6 +2040,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
.collect()
|
||||
})
|
||||
};
|
||||
debug!("visit_segment_args: unsubst={:?}", unsubst);
|
||||
unsubst
|
||||
.iter()
|
||||
.map(|set| match *set {
|
||||
|
|
@ -2023,6 +2061,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
.collect()
|
||||
});
|
||||
|
||||
debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
|
||||
|
||||
let mut i = 0;
|
||||
for arg in &generic_args.args {
|
||||
match arg {
|
||||
|
|
@ -2045,8 +2085,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Hack: when resolving the type `XX` in binding like `dyn
|
||||
// Foo<'b, Item = XX>`, the current object-lifetime default
|
||||
// would be to examine the trait `Foo` to check whether it has
|
||||
// a lifetime bound declared on `Item`. e.g., if `Foo` is
|
||||
// declared like so, then the default object lifetime bound in
|
||||
// `XX` should be `'b`:
|
||||
//
|
||||
// ```rust
|
||||
// trait Foo<'a> {
|
||||
// type Item: 'a;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// but if we just have `type Item;`, then it would be
|
||||
// `'static`. However, we don't get all of this logic correct.
|
||||
//
|
||||
// Instead, we do something hacky: if there are no lifetime parameters
|
||||
// to the trait, then we simply use a default object lifetime
|
||||
// bound of `'static`, because there is no other possibility. On the other hand,
|
||||
// if there ARE lifetime parameters, then we require the user to give an
|
||||
// explicit bound for now.
|
||||
//
|
||||
// This is intended to leave room for us to implement the
|
||||
// correct behavior in the future.
|
||||
let has_lifetime_parameter = generic_args
|
||||
.args
|
||||
.iter()
|
||||
.any(|arg| match arg {
|
||||
GenericArg::Lifetime(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
// Resolve lifetimes found in the type `XX` from `Item = XX` bindings.
|
||||
for b in &generic_args.bindings {
|
||||
self.visit_assoc_type_binding(b);
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: if has_lifetime_parameter {
|
||||
None
|
||||
} else {
|
||||
Some(Region::Static)
|
||||
},
|
||||
s: self.scope,
|
||||
};
|
||||
self.with(scope, |_, this| this.visit_assoc_type_binding(b));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2347,6 +2428,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) {
|
||||
debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs);
|
||||
|
||||
if lifetime_refs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2539,6 +2622,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
|
||||
let mut late_depth = 0;
|
||||
let mut scope = self.scope;
|
||||
let lifetime = loop {
|
||||
|
|
@ -2638,6 +2722,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
|
||||
self.resolve_lifetime_ref(lt);
|
||||
}
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
lt.span,
|
||||
"lowering generated `ImplicitObjectLifetimeDefault` \
|
||||
outside of an object type",
|
||||
)
|
||||
}
|
||||
hir::LifetimeName::Error => {
|
||||
// No need to do anything, error already reported.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
|
|||
///
|
||||
/// zsts can't be read out of two reasons:
|
||||
/// * byteorder cannot work with zero element buffers
|
||||
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
|
||||
/// * in order to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
|
||||
/// being valid for ZSTs
|
||||
///
|
||||
/// It is the caller's responsibility to check bounds and alignment beforehand.
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
|
|||
pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> {
|
||||
match self {
|
||||
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
|
||||
ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::from_bytes(0))),
|
||||
ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::ZERO)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -248,10 +248,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
/// This is always inlined, despite its size, because it has a single
|
||||
/// callsite and it is called *very* frequently.
|
||||
#[inline(always)]
|
||||
fn process_obligation(&mut self,
|
||||
pending_obligation: &mut Self::Obligation)
|
||||
-> ProcessResult<Self::Obligation, Self::Error>
|
||||
{
|
||||
fn process_obligation(
|
||||
&mut self,
|
||||
pending_obligation: &mut Self::Obligation,
|
||||
) -> ProcessResult<Self::Obligation, Self::Error> {
|
||||
// if we were stalled on some unresolved variables, first check
|
||||
// whether any of them have been resolved; if not, don't bother
|
||||
// doing more work yet
|
||||
|
|
@ -277,7 +277,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate);
|
||||
}
|
||||
|
||||
debug!("process_obligation: obligation = {:?}", obligation);
|
||||
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
|
||||
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
|
|
@ -425,10 +425,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
match ty::wf::obligations(self.selcx.infcx(),
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
ty, obligation.cause.span) {
|
||||
match ty::wf::obligations(
|
||||
self.selcx.infcx(),
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
ty,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
None => {
|
||||
pending_obligation.stalled_on = vec![ty];
|
||||
ProcessResult::Unchanged
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
|
||||
-> Vec<ObjectSafetyViolation>
|
||||
{
|
||||
debug_assert!(self.generics_of(trait_def_id).has_self);
|
||||
let violations = traits::supertrait_def_ids(self, trait_def_id)
|
||||
.filter(|&def_id| self.predicates_reference_self(def_id, true))
|
||||
.map(|_| ObjectSafetyViolation::SupertraitSelf)
|
||||
|
|
@ -106,6 +107,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn object_safety_violations(self, trait_def_id: DefId)
|
||||
-> Vec<ObjectSafetyViolation>
|
||||
{
|
||||
debug_assert!(self.generics_of(trait_def_id).has_self);
|
||||
debug!("object_safety_violations: {:?}", trait_def_id);
|
||||
|
||||
traits::supertrait_def_ids(self, trait_def_id)
|
||||
|
|
@ -113,9 +115,25 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn object_safety_violations_for_trait(self, trait_def_id: DefId)
|
||||
-> Vec<ObjectSafetyViolation>
|
||||
{
|
||||
/// We say a method is *vtable safe* if it can be invoked on a trait
|
||||
/// object. Note that object-safe traits can have some
|
||||
/// non-vtable-safe methods, so long as they require `Self:Sized` or
|
||||
/// otherwise ensure that they cannot be used when `Self=Trait`.
|
||||
pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
|
||||
debug_assert!(self.generics_of(trait_def_id).has_self);
|
||||
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
|
||||
// Any method that has a `Self : Sized` requisite can't be called.
|
||||
if self.generics_require_sized_self(method.def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.virtual_call_violation_for_method(trait_def_id, method) {
|
||||
None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
|
||||
Some(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
|
||||
// Check methods for violations.
|
||||
let mut violations: Vec<_> = self.associated_items(trait_def_id)
|
||||
.filter(|item| item.kind == ty::AssocKind::Method)
|
||||
|
|
@ -163,14 +181,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
fn predicates_reference_self(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
supertraits_only: bool) -> bool
|
||||
{
|
||||
supertraits_only: bool,
|
||||
) -> bool {
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
|
||||
let predicates = if supertraits_only {
|
||||
self.super_predicates_of(trait_def_id)
|
||||
} else {
|
||||
self.predicates_of(trait_def_id)
|
||||
};
|
||||
let self_ty = self.types.self_param;
|
||||
let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty);
|
||||
predicates
|
||||
.predicates
|
||||
.iter()
|
||||
|
|
@ -179,7 +199,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
match predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
// In the case of a trait predicate, we can skip the "self" type.
|
||||
data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
|
||||
data.skip_binder().input_types().skip(1).any(has_self_ty)
|
||||
}
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
// And similarly for projections. This should be redundant with
|
||||
|
|
@ -199,7 +219,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.trait_ref(self)
|
||||
.input_types()
|
||||
.skip(1)
|
||||
.any(|t| t.has_self_ty())
|
||||
.any(has_self_ty)
|
||||
}
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
|
|
@ -229,11 +249,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let predicates = predicates.instantiate_identity(self).predicates;
|
||||
elaborate_predicates(self, predicates)
|
||||
.any(|predicate| match predicate {
|
||||
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
|
||||
trait_pred.skip_binder().self_ty().is_self()
|
||||
ty::Predicate::Trait(ref trait_pred) => {
|
||||
trait_pred.def_id() == sized_def_id
|
||||
&& trait_pred.skip_binder().self_ty().is_param(0)
|
||||
}
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::WellFormed(..) |
|
||||
|
|
@ -248,11 +268,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
/// Returns `Some(_)` if this method makes the containing trait not object safe.
|
||||
fn object_safety_violation_for_method(self,
|
||||
trait_def_id: DefId,
|
||||
method: &ty::AssocItem)
|
||||
-> Option<MethodViolationCode>
|
||||
{
|
||||
fn object_safety_violation_for_method(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
method: &ty::AssocItem,
|
||||
) -> Option<MethodViolationCode> {
|
||||
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
|
||||
// Any method that has a `Self : Sized` requisite is otherwise
|
||||
// exempt from the regulations.
|
||||
|
|
@ -263,36 +283,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.virtual_call_violation_for_method(trait_def_id, method)
|
||||
}
|
||||
|
||||
/// We say a method is *vtable safe* if it can be invoked on a trait
|
||||
/// object. Note that object-safe traits can have some
|
||||
/// non-vtable-safe methods, so long as they require `Self:Sized` or
|
||||
/// otherwise ensure that they cannot be used when `Self=Trait`.
|
||||
pub fn is_vtable_safe_method(self,
|
||||
trait_def_id: DefId,
|
||||
method: &ty::AssocItem)
|
||||
-> bool
|
||||
{
|
||||
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
|
||||
// Any method that has a `Self : Sized` requisite can't be called.
|
||||
if self.generics_require_sized_self(method.def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.virtual_call_violation_for_method(trait_def_id, method) {
|
||||
None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
|
||||
Some(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Some(_)` if this method cannot be called on a trait
|
||||
/// object; this does not necessarily imply that the enclosing trait
|
||||
/// is not object safe, because the method might have a where clause
|
||||
/// `Self:Sized`.
|
||||
fn virtual_call_violation_for_method(self,
|
||||
trait_def_id: DefId,
|
||||
method: &ty::AssocItem)
|
||||
-> Option<MethodViolationCode>
|
||||
{
|
||||
fn virtual_call_violation_for_method(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
method: &ty::AssocItem,
|
||||
) -> Option<MethodViolationCode> {
|
||||
// The method's first parameter must be named `self`
|
||||
if !method.method_has_self_argument {
|
||||
return Some(MethodViolationCode::StaticMethod);
|
||||
|
|
@ -323,7 +322,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.collect::<Vec<_>>()
|
||||
// Do a shallow visit so that `contains_illegal_self_type_reference`
|
||||
// may apply it's custom visiting.
|
||||
.visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
|
||||
.visit_tys_shallow(|t| {
|
||||
self.contains_illegal_self_type_reference(trait_def_id, t)
|
||||
}) {
|
||||
let span = self.def_span(method.def_id);
|
||||
return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
|
||||
}
|
||||
|
|
@ -337,7 +338,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// However, this is already considered object-safe. We allow it as a special case here.
|
||||
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
|
||||
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`
|
||||
if receiver_ty != self.mk_self_type() {
|
||||
if receiver_ty != self.types.self_param {
|
||||
if !self.receiver_is_dispatchable(method, receiver_ty) {
|
||||
return Some(MethodViolationCode::UndispatchableReceiver);
|
||||
} else {
|
||||
|
|
@ -404,7 +405,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Performs a type substitution to produce the version of receiver_ty when `Self = self_ty`
|
||||
/// e.g., for receiver_ty = `Rc<Self>` and self_ty = `Foo`, returns `Rc<Foo>`.
|
||||
fn receiver_for_self_ty(
|
||||
self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId
|
||||
self,
|
||||
receiver_ty: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
method_def_id: DefId,
|
||||
) -> Ty<'tcx> {
|
||||
debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
|
||||
let substs = InternalSubsts::for_item(self, method_def_id, |param, _| {
|
||||
|
|
@ -555,7 +559,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// Self: Unsize<U>
|
||||
let unsize_predicate = ty::TraitRef {
|
||||
def_id: unsize_did,
|
||||
substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]),
|
||||
substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]),
|
||||
}.to_predicate();
|
||||
|
||||
// U: Trait<Arg1, ..., ArgN>
|
||||
|
|
@ -608,11 +612,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn contains_illegal_self_type_reference(self,
|
||||
trait_def_id: DefId,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
fn contains_illegal_self_type_reference(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
// This is somewhat subtle. In general, we want to forbid
|
||||
// references to `Self` in the argument and return types,
|
||||
// since the value of `Self` is erased. However, there is one
|
||||
|
|
@ -654,10 +658,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
|
||||
let mut error = false;
|
||||
let self_ty = self.types.self_param;
|
||||
ty.maybe_walk(|ty| {
|
||||
match ty.sty {
|
||||
ty::Param(ref param_ty) => {
|
||||
if param_ty.is_self() {
|
||||
ty::Param(_) => {
|
||||
if ty == self_ty {
|
||||
error = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ pub struct CommonTypes<'tcx> {
|
|||
pub f32: Ty<'tcx>,
|
||||
pub f64: Ty<'tcx>,
|
||||
pub never: Ty<'tcx>,
|
||||
pub self_param: Ty<'tcx>,
|
||||
pub err: Ty<'tcx>,
|
||||
|
||||
/// Dummy type used for the `Self` of a `TraitRef` created for converting
|
||||
|
|
@ -915,6 +916,10 @@ impl<'tcx> CommonTypes<'tcx> {
|
|||
u128: mk(Uint(ast::UintTy::U128)),
|
||||
f32: mk(Float(ast::FloatTy::F32)),
|
||||
f64: mk(Float(ast::FloatTy::F64)),
|
||||
self_param: mk(ty::Param(ty::ParamTy {
|
||||
index: 0,
|
||||
name: kw::SelfUpper.as_interned_str(),
|
||||
})),
|
||||
|
||||
trait_object_dummy_self: mk(Infer(ty::FreshTy(0))),
|
||||
}
|
||||
|
|
@ -2566,10 +2571,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mk_self_type(self) -> Ty<'tcx> {
|
||||
self.mk_ty_param(0, kw::SelfUpper.as_interned_str())
|
||||
}
|
||||
|
||||
pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> {
|
||||
match param.kind {
|
||||
|
|
|
|||
|
|
@ -239,13 +239,7 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
|
||||
ty::Projection(_) => "associated type".into(),
|
||||
ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
|
||||
ty::Param(ref p) => {
|
||||
if p.is_self() {
|
||||
"Self".into()
|
||||
} else {
|
||||
"type parameter".into()
|
||||
}
|
||||
}
|
||||
ty::Param(_) => "type parameter".into(),
|
||||
ty::Opaque(..) => "opaque type".into(),
|
||||
ty::Error => "type error".into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ty::subst::{SubstsRef, UnpackedKind};
|
||||
use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst};
|
||||
use crate::ty::{self, Ty, TypeFlags, InferConst};
|
||||
use crate::mir::interpret::ConstValue;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -86,13 +86,9 @@ impl FlagComputation {
|
|||
self.add_flags(TypeFlags::HAS_TY_ERR)
|
||||
}
|
||||
|
||||
&ty::Param(ref p) => {
|
||||
&ty::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
|
||||
if p.is_self() {
|
||||
self.add_flags(TypeFlags::HAS_SELF);
|
||||
} else {
|
||||
self.add_flags(TypeFlags::HAS_PARAMS);
|
||||
}
|
||||
self.add_flags(TypeFlags::HAS_PARAMS);
|
||||
}
|
||||
|
||||
&ty::Generator(_, ref substs, _) => {
|
||||
|
|
@ -143,11 +139,6 @@ impl FlagComputation {
|
|||
}
|
||||
|
||||
&ty::Projection(ref data) => {
|
||||
// currently we can't normalize projections that
|
||||
// include bound regions, so track those separately.
|
||||
if !data.has_escaping_bound_vars() {
|
||||
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
|
||||
}
|
||||
self.add_flags(TypeFlags::HAS_PROJECTION);
|
||||
self.add_projection_ty(data);
|
||||
}
|
||||
|
|
@ -243,7 +234,7 @@ impl FlagComputation {
|
|||
match c.val {
|
||||
ConstValue::Unevaluated(_, substs) => {
|
||||
self.add_substs(substs);
|
||||
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION);
|
||||
self.add_flags(TypeFlags::HAS_PROJECTION);
|
||||
},
|
||||
ConstValue::Infer(infer) => {
|
||||
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER);
|
||||
|
|
|
|||
|
|
@ -85,9 +85,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
|
|||
fn has_param_types(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_PARAMS)
|
||||
}
|
||||
fn has_self_ty(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_SELF)
|
||||
}
|
||||
fn has_infer_types(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,8 +298,9 @@ impl<'tcx> Instance<'tcx> {
|
|||
) -> Option<Instance<'tcx>> {
|
||||
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
|
||||
let fn_sig = tcx.fn_sig(def_id);
|
||||
let is_vtable_shim =
|
||||
fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_self();
|
||||
let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0
|
||||
&& fn_sig.input(0).skip_binder().is_param(0)
|
||||
&& tcx.generics_of(def_id).has_self;
|
||||
if is_vtable_shim {
|
||||
debug!(" => associated item with unsizeable self: Self");
|
||||
Some(Instance {
|
||||
|
|
|
|||
|
|
@ -1601,7 +1601,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
// resulting from the final codegen session.
|
||||
if
|
||||
layout.ty.has_param_types() ||
|
||||
layout.ty.has_self_ty() ||
|
||||
!self.param_env.caller_bounds.is_empty()
|
||||
{
|
||||
return;
|
||||
|
|
@ -1767,7 +1766,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
||||
match tail.sty {
|
||||
ty::Param(_) | ty::Projection(_) => {
|
||||
debug_assert!(tail.has_param_types() || tail.has_self_ty());
|
||||
debug_assert!(tail.has_param_types());
|
||||
Ok(SizeSkeleton::Pointer {
|
||||
non_zero,
|
||||
tail: tcx.erase_regions(&tail)
|
||||
|
|
|
|||
|
|
@ -414,61 +414,53 @@ pub struct CReaderCacheKey {
|
|||
bitflags! {
|
||||
pub struct TypeFlags: u32 {
|
||||
const HAS_PARAMS = 1 << 0;
|
||||
const HAS_SELF = 1 << 1;
|
||||
const HAS_TY_INFER = 1 << 2;
|
||||
const HAS_RE_INFER = 1 << 3;
|
||||
const HAS_RE_PLACEHOLDER = 1 << 4;
|
||||
const HAS_TY_INFER = 1 << 1;
|
||||
const HAS_RE_INFER = 1 << 2;
|
||||
const HAS_RE_PLACEHOLDER = 1 << 3;
|
||||
|
||||
/// Does this have any `ReEarlyBound` regions? Used to
|
||||
/// determine whether substitition is required, since those
|
||||
/// represent regions that are bound in a `ty::Generics` and
|
||||
/// hence may be substituted.
|
||||
const HAS_RE_EARLY_BOUND = 1 << 5;
|
||||
const HAS_RE_EARLY_BOUND = 1 << 4;
|
||||
|
||||
/// Does this have any region that "appears free" in the type?
|
||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||
const HAS_FREE_REGIONS = 1 << 6;
|
||||
const HAS_FREE_REGIONS = 1 << 5;
|
||||
|
||||
/// Is an error type reachable?
|
||||
const HAS_TY_ERR = 1 << 7;
|
||||
const HAS_PROJECTION = 1 << 8;
|
||||
const HAS_TY_ERR = 1 << 6;
|
||||
const HAS_PROJECTION = 1 << 7;
|
||||
|
||||
// FIXME: Rename this to the actual property since it's used for generators too
|
||||
const HAS_TY_CLOSURE = 1 << 9;
|
||||
const HAS_TY_CLOSURE = 1 << 8;
|
||||
|
||||
/// `true` if there are "names" of types and regions and so forth
|
||||
/// that are local to a particular fn
|
||||
const HAS_FREE_LOCAL_NAMES = 1 << 10;
|
||||
const HAS_FREE_LOCAL_NAMES = 1 << 9;
|
||||
|
||||
/// Present if the type belongs in a local type context.
|
||||
/// Only set for Infer other than Fresh.
|
||||
const KEEP_IN_LOCAL_TCX = 1 << 11;
|
||||
|
||||
// Is there a projection that does not involve a bound region?
|
||||
// Currently we can't normalize projections w/ bound regions.
|
||||
const HAS_NORMALIZABLE_PROJECTION = 1 << 12;
|
||||
const KEEP_IN_LOCAL_TCX = 1 << 10;
|
||||
|
||||
/// Does this have any `ReLateBound` regions? Used to check
|
||||
/// if a global bound is safe to evaluate.
|
||||
const HAS_RE_LATE_BOUND = 1 << 13;
|
||||
const HAS_RE_LATE_BOUND = 1 << 11;
|
||||
|
||||
const HAS_TY_PLACEHOLDER = 1 << 14;
|
||||
const HAS_TY_PLACEHOLDER = 1 << 12;
|
||||
|
||||
const HAS_CT_INFER = 1 << 15;
|
||||
const HAS_CT_PLACEHOLDER = 1 << 16;
|
||||
const HAS_CT_INFER = 1 << 13;
|
||||
const HAS_CT_PLACEHOLDER = 1 << 14;
|
||||
|
||||
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
||||
TypeFlags::HAS_SELF.bits |
|
||||
TypeFlags::HAS_RE_EARLY_BOUND.bits;
|
||||
|
||||
/// Flags representing the nominal content of a type,
|
||||
/// computed by FlagsComputation. If you add a new nominal
|
||||
/// flag, it should be added here too.
|
||||
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
|
||||
TypeFlags::HAS_SELF.bits |
|
||||
TypeFlags::HAS_TY_INFER.bits |
|
||||
TypeFlags::HAS_RE_INFER.bits |
|
||||
TypeFlags::HAS_CT_INFER.bits |
|
||||
TypeFlags::HAS_RE_PLACEHOLDER.bits |
|
||||
TypeFlags::HAS_RE_EARLY_BOUND.bits |
|
||||
TypeFlags::HAS_FREE_REGIONS.bits |
|
||||
|
|
@ -479,6 +471,7 @@ bitflags! {
|
|||
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
|
||||
TypeFlags::HAS_RE_LATE_BOUND.bits |
|
||||
TypeFlags::HAS_TY_PLACEHOLDER.bits |
|
||||
TypeFlags::HAS_CT_INFER.bits |
|
||||
TypeFlags::HAS_CT_PLACEHOLDER.bits;
|
||||
}
|
||||
}
|
||||
|
|
@ -1734,7 +1727,6 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||
if value.has_placeholders()
|
||||
|| value.needs_infer()
|
||||
|| value.has_param_types()
|
||||
|| value.has_self_ty()
|
||||
{
|
||||
ParamEnvAnd {
|
||||
param_env: self,
|
||||
|
|
|
|||
|
|
@ -1141,13 +1141,6 @@ impl<'tcx> ParamTy {
|
|||
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
tcx.mk_ty_param(self.index, self.name)
|
||||
}
|
||||
|
||||
pub fn is_self(&self) -> bool {
|
||||
// FIXME(#50125): Ignoring `Self` with `index != 0` might lead to weird behavior elsewhere,
|
||||
// but this should only be possible when using `-Z continue-parse-after-error` like
|
||||
// `compile-fail/issue-36638.rs`.
|
||||
self.name.as_symbol() == kw::SelfUpper && self.index == 0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable,
|
||||
|
|
@ -1789,14 +1782,6 @@ impl<'tcx> TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_self(&self) -> bool {
|
||||
match self.sty {
|
||||
Param(ref p) => p.is_self(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_slice(&self) -> bool {
|
||||
match self.sty {
|
||||
|
|
|
|||
|
|
@ -333,15 +333,21 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
offset: Size,
|
||||
) -> PlaceRef<'tcx, &'ll Value> {
|
||||
assert_eq!(alloc.align, layout.align.abi);
|
||||
let init = const_alloc_to_llvm(self, alloc);
|
||||
let base_addr = self.static_addr_of(init, alloc.align, None);
|
||||
let llty = self.type_ptr_to(layout.llvm_type(self));
|
||||
let llval = if layout.size == Size::ZERO {
|
||||
let llval = self.const_usize(alloc.align.bytes());
|
||||
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
|
||||
} else {
|
||||
let init = const_alloc_to_llvm(self, alloc);
|
||||
let base_addr = self.static_addr_of(init, alloc.align, None);
|
||||
|
||||
let llval = unsafe { llvm::LLVMConstInBoundsGEP(
|
||||
self.const_bitcast(base_addr, self.type_i8p()),
|
||||
&self.const_usize(offset.bytes()),
|
||||
1,
|
||||
)};
|
||||
let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self)));
|
||||
let llval = unsafe { llvm::LLVMConstInBoundsGEP(
|
||||
self.const_bitcast(base_addr, self.type_i8p()),
|
||||
&self.const_usize(offset.bytes()),
|
||||
1,
|
||||
)};
|
||||
self.const_bitcast(llval, llty)
|
||||
};
|
||||
PlaceRef::new_sized(llval, layout, alloc.align)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
|
|||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
rustc_plugin_impl = { path = "../librustc_plugin" }
|
||||
rustc_save_analysis = { path = "../librustc_save_analysis" }
|
||||
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
|
||||
rustc_interface = { path = "../librustc_interface" }
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ extern crate libc;
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub extern crate rustc_plugin_impl as plugin;
|
||||
|
||||
use pretty::{PpMode, UserIdentifiedItem};
|
||||
|
||||
//use rustc_resolve as resolve;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ rustc_passes = { path = "../librustc_passes" }
|
|||
rustc_typeck = { path = "../librustc_typeck" }
|
||||
rustc_lint = { path = "../librustc_lint" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_plugin = { path = "../librustc_plugin" }
|
||||
rustc_plugin = { path = "../librustc_plugin", package = "rustc_plugin_impl" }
|
||||
rustc_privacy = { path = "../librustc_privacy" }
|
||||
rustc_resolve = { path = "../librustc_resolve" }
|
||||
tempfile = "3.0.5"
|
||||
|
|
|
|||
|
|
@ -352,7 +352,6 @@ impl Cursor<'_> {
|
|||
loop {
|
||||
match self.nth_char(0) {
|
||||
'\n' => break,
|
||||
'\r' if self.nth_char(1) == '\n' => break,
|
||||
EOF_CHAR if self.is_eof() => break,
|
||||
_ => {
|
||||
self.bump();
|
||||
|
|
@ -525,7 +524,6 @@ impl Cursor<'_> {
|
|||
match self.nth_char(0) {
|
||||
'/' if !first => break,
|
||||
'\n' if self.nth_char(1) != '\'' => break,
|
||||
'\r' if self.nth_char(1) == '\n' => break,
|
||||
EOF_CHAR if self.is_eof() => break,
|
||||
'\'' => {
|
||||
self.bump();
|
||||
|
|
|
|||
|
|
@ -128,11 +128,7 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<ch
|
|||
if first_char != '\\' {
|
||||
return match first_char {
|
||||
'\t' | '\n' => Err(EscapeError::EscapeOnlyChar),
|
||||
'\r' => Err(if chars.clone().next() == Some('\n') {
|
||||
EscapeError::EscapeOnlyChar
|
||||
} else {
|
||||
EscapeError::BareCarriageReturn
|
||||
}),
|
||||
'\r' => Err(EscapeError::BareCarriageReturn),
|
||||
'\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar),
|
||||
'"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar),
|
||||
_ => {
|
||||
|
|
@ -244,27 +240,15 @@ where
|
|||
|
||||
let unescaped_char = match first_char {
|
||||
'\\' => {
|
||||
let (second_char, third_char) = {
|
||||
let mut chars = chars.clone();
|
||||
(chars.next(), chars.next())
|
||||
};
|
||||
match (second_char, third_char) {
|
||||
(Some('\n'), _) | (Some('\r'), Some('\n')) => {
|
||||
let second_char = chars.clone().next();
|
||||
match second_char {
|
||||
Some('\n') => {
|
||||
skip_ascii_whitespace(&mut chars);
|
||||
continue;
|
||||
}
|
||||
_ => scan_escape(first_char, &mut chars, mode),
|
||||
}
|
||||
}
|
||||
'\r' => {
|
||||
let second_char = chars.clone().next();
|
||||
if second_char == Some('\n') {
|
||||
chars.next();
|
||||
Ok('\n')
|
||||
} else {
|
||||
scan_escape(first_char, &mut chars, mode)
|
||||
}
|
||||
}
|
||||
'\n' => Ok('\n'),
|
||||
'\t' => Ok('\t'),
|
||||
_ => scan_escape(first_char, &mut chars, mode),
|
||||
|
|
@ -298,15 +282,11 @@ where
|
|||
while let Some(curr) = chars.next() {
|
||||
let start = initial_len - chars.as_str().len() - curr.len_utf8();
|
||||
|
||||
let result = match (curr, chars.clone().next()) {
|
||||
('\r', Some('\n')) => {
|
||||
chars.next();
|
||||
Ok('\n')
|
||||
},
|
||||
('\r', _) => Err(EscapeError::BareCarriageReturnInRawString),
|
||||
(c, _) if mode.is_bytes() && !c.is_ascii() =>
|
||||
let result = match curr {
|
||||
'\r' => Err(EscapeError::BareCarriageReturnInRawString),
|
||||
c if mode.is_bytes() && !c.is_ascii() =>
|
||||
Err(EscapeError::NonAsciiCharInByteString),
|
||||
(c, _) => Ok(c),
|
||||
c => Ok(c),
|
||||
};
|
||||
let end = initial_len - chars.as_str().len();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ fn test_unescape_char_bad() {
|
|||
check(r"\", EscapeError::LoneSlash);
|
||||
|
||||
check("\n", EscapeError::EscapeOnlyChar);
|
||||
check("\r\n", EscapeError::EscapeOnlyChar);
|
||||
check("\t", EscapeError::EscapeOnlyChar);
|
||||
check("'", EscapeError::EscapeOnlyChar);
|
||||
check("\r", EscapeError::BareCarriageReturn);
|
||||
|
|
@ -31,6 +30,7 @@ fn test_unescape_char_bad() {
|
|||
check(r"\v", EscapeError::InvalidEscape);
|
||||
check(r"\💩", EscapeError::InvalidEscape);
|
||||
check(r"\●", EscapeError::InvalidEscape);
|
||||
check("\\\r", EscapeError::InvalidEscape);
|
||||
|
||||
check(r"\x", EscapeError::TooShortHexEscape);
|
||||
check(r"\x0", EscapeError::TooShortHexEscape);
|
||||
|
|
@ -116,10 +116,9 @@ fn test_unescape_str_good() {
|
|||
|
||||
check("foo", "foo");
|
||||
check("", "");
|
||||
check(" \t\n\r\n", " \t\n\n");
|
||||
check(" \t\n", " \t\n");
|
||||
|
||||
check("hello \\\n world", "hello world");
|
||||
check("hello \\\r\n world", "hello world");
|
||||
check("thread's", "thread's")
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +133,6 @@ fn test_unescape_byte_bad() {
|
|||
check(r"\", EscapeError::LoneSlash);
|
||||
|
||||
check("\n", EscapeError::EscapeOnlyChar);
|
||||
check("\r\n", EscapeError::EscapeOnlyChar);
|
||||
check("\t", EscapeError::EscapeOnlyChar);
|
||||
check("'", EscapeError::EscapeOnlyChar);
|
||||
check("\r", EscapeError::BareCarriageReturn);
|
||||
|
|
@ -238,10 +236,9 @@ fn test_unescape_byte_str_good() {
|
|||
|
||||
check("foo", b"foo");
|
||||
check("", b"");
|
||||
check(" \t\n\r\n", b" \t\n\n");
|
||||
check(" \t\n", b" \t\n");
|
||||
|
||||
check("hello \\\n world", b"hello world");
|
||||
check("hello \\\r\n world", b"hello world");
|
||||
check("thread's", b"thread's")
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +250,6 @@ fn test_unescape_raw_str() {
|
|||
assert_eq!(unescaped, expected);
|
||||
}
|
||||
|
||||
check("\r\n", &[(0..2, Ok('\n'))]);
|
||||
check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
|
||||
check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]);
|
||||
}
|
||||
|
|
@ -266,7 +262,6 @@ fn test_unescape_raw_byte_str() {
|
|||
assert_eq!(unescaped, expected);
|
||||
}
|
||||
|
||||
check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]);
|
||||
check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
|
||||
check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]);
|
||||
check(
|
||||
|
|
|
|||
|
|
@ -1876,16 +1876,70 @@ declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
|
|||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {
|
||||
|
||||
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
|
||||
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum InitKind { Zeroed, Uninit };
|
||||
|
||||
/// Information about why a type cannot be initialized this way.
|
||||
/// Contains an error message and optionally a span to point at.
|
||||
type InitError = (String, Option<Span>);
|
||||
|
||||
/// Test if this constant is all-0.
|
||||
fn is_zero(expr: &hir::Expr) -> bool {
|
||||
use hir::ExprKind::*;
|
||||
use syntax::ast::LitKind::*;
|
||||
match &expr.node {
|
||||
Lit(lit) =>
|
||||
if let Int(i, _) = lit.node {
|
||||
i == 0
|
||||
} else {
|
||||
false
|
||||
},
|
||||
Tup(tup) =>
|
||||
tup.iter().all(is_zero),
|
||||
_ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if this expression is a "dangerous initialization".
|
||||
fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<InitKind> {
|
||||
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
|
||||
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
|
||||
// `transmute` is inside an anonymous module (the `extern` block?);
|
||||
// `Invalid` represents the empty string and matches that.
|
||||
const TRANSMUTE_PATH: &[Symbol] =
|
||||
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];
|
||||
|
||||
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.node {
|
||||
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
|
||||
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
|
||||
|
||||
if cx.match_def_path(def_id, ZEROED_PATH) {
|
||||
return Some(InitKind::Zeroed);
|
||||
}
|
||||
if cx.match_def_path(def_id, UININIT_PATH) {
|
||||
return Some(InitKind::Uninit);
|
||||
}
|
||||
if cx.match_def_path(def_id, TRANSMUTE_PATH) {
|
||||
if is_zero(&args[0]) {
|
||||
return Some(InitKind::Zeroed);
|
||||
}
|
||||
}
|
||||
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
|
||||
// `MaybeUninit::uninit().assume_init()`.
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Return `Some` only if we are sure this type does *not*
|
||||
/// allow zero initialization.
|
||||
fn ty_find_init_error<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<InitError> {
|
||||
fn ty_find_init_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
init: InitKind,
|
||||
) -> Option<InitError> {
|
||||
use rustc::ty::TyKind::*;
|
||||
match ty.sty {
|
||||
// Primitive types that don't like 0 as a value.
|
||||
|
|
@ -1893,8 +1947,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
|||
Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)),
|
||||
FnPtr(..) => Some((format!("Function pointers must be non-null"), None)),
|
||||
Never => Some((format!("The never type (`!`) has no valid value"), None)),
|
||||
// Recurse for some compound types.
|
||||
// Primitive types with other constraints.
|
||||
Bool if init == InitKind::Uninit =>
|
||||
Some((format!("Booleans must be `true` or `false`"), None)),
|
||||
Char if init == InitKind::Uninit =>
|
||||
Some((format!("Characters must be a valid unicode codepoint"), None)),
|
||||
// Recurse and checks for some compound types.
|
||||
Adt(adt_def, substs) if !adt_def.is_union() => {
|
||||
// First check f this ADT has a layout attribute (like `NonNull` and friends).
|
||||
use std::ops::Bound;
|
||||
match tcx.layout_scalar_valid_range(adt_def.did) {
|
||||
// We exploit here that `layout_scalar_valid_range` will never
|
||||
// return `Bound::Excluded`. (And we have tests checking that we
|
||||
// handle the attribute correctly.)
|
||||
(Bound::Included(lo), _) if lo > 0 =>
|
||||
return Some((format!("{} must be non-null", ty), None)),
|
||||
(Bound::Included(_), _) | (_, Bound::Included(_))
|
||||
if init == InitKind::Uninit =>
|
||||
return Some((
|
||||
format!("{} must be initialized inside its custom valid range", ty),
|
||||
None,
|
||||
)),
|
||||
_ => {}
|
||||
}
|
||||
// Now, recurse.
|
||||
match adt_def.variants.len() {
|
||||
0 => Some((format!("0-variant enums have no valid value"), None)),
|
||||
1 => {
|
||||
|
|
@ -1905,6 +1981,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
|||
ty_find_init_error(
|
||||
tcx,
|
||||
field.ty(tcx, substs),
|
||||
init,
|
||||
).map(|(mut msg, span)| if span.is_none() {
|
||||
// Point to this field, should be helpful for figuring
|
||||
// out where the source of the error is.
|
||||
|
|
@ -1918,57 +1995,48 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
|||
})
|
||||
})
|
||||
}
|
||||
// Multi-variant enums are tricky: if all but one variant are
|
||||
// uninhabited, we might actually do layout like for a single-variant
|
||||
// enum, and then even leaving them uninitialized could be okay.
|
||||
_ => None, // Conservative fallback for multi-variant enum.
|
||||
}
|
||||
}
|
||||
Tuple(..) => {
|
||||
// Proceed recursively, check all fields.
|
||||
ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field))
|
||||
ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field, init))
|
||||
}
|
||||
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
|
||||
// FIXME: *Only for `mem::uninitialized`*, we could also warn for `bool`,
|
||||
// `char`, and any multivariant enum.
|
||||
// Conservative fallback.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
|
||||
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
|
||||
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
|
||||
if cx.match_def_path(def_id, &ZEROED_PATH) ||
|
||||
cx.match_def_path(def_id, &UININIT_PATH)
|
||||
{
|
||||
// This conjures an instance of a type out of nothing,
|
||||
// using zeroed or uninitialized memory.
|
||||
// We are extremely conservative with what we warn about.
|
||||
let conjured_ty = cx.tables.expr_ty(expr);
|
||||
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty) {
|
||||
let mut err = cx.struct_span_lint(
|
||||
INVALID_VALUE,
|
||||
expr.span,
|
||||
&format!(
|
||||
"the type `{}` does not permit {}",
|
||||
conjured_ty,
|
||||
if cx.match_def_path(def_id, &ZEROED_PATH) {
|
||||
"zero-initialization"
|
||||
} else {
|
||||
"being left uninitialized"
|
||||
}
|
||||
),
|
||||
);
|
||||
err.span_label(expr.span,
|
||||
"this code causes undefined behavior when executed");
|
||||
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
|
||||
if let Some(span) = span {
|
||||
err.span_note(span, &msg);
|
||||
} else {
|
||||
err.note(&msg);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
if let Some(init) = is_dangerous_init(cx, expr) {
|
||||
// This conjures an instance of a type out of nothing,
|
||||
// using zeroed or uninitialized memory.
|
||||
// We are extremely conservative with what we warn about.
|
||||
let conjured_ty = cx.tables.expr_ty(expr);
|
||||
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
|
||||
let mut err = cx.struct_span_lint(
|
||||
INVALID_VALUE,
|
||||
expr.span,
|
||||
&format!(
|
||||
"the type `{}` does not permit {}",
|
||||
conjured_ty,
|
||||
match init {
|
||||
InitKind::Zeroed => "zero-initialization",
|
||||
InitKind::Uninit => "being left uninitialized",
|
||||
},
|
||||
),
|
||||
);
|
||||
err.span_label(expr.span,
|
||||
"this code causes undefined behavior when executed");
|
||||
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
|
||||
if let Some(span) = span {
|
||||
err.span_note(span, &msg);
|
||||
} else {
|
||||
err.note(&msg);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! This currently only contains the definitions and implementations
|
||||
//! of most of the lints that `rustc` supports directly, it does not
|
||||
//! contain the infrastructure for defining/registering lints. That is
|
||||
//! available in `rustc::lint` and `rustc_plugin` respectively.
|
||||
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
|
||||
//!
|
||||
//! ## Note
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
use crate::cstore::{self, CStore, CrateSource, MetadataBlob};
|
||||
use crate::locator::{self, CratePaths};
|
||||
use crate::decoder::proc_macro_def_path_table;
|
||||
use crate::schema::CrateRoot;
|
||||
use crate::schema::{CrateRoot};
|
||||
use rustc_data_structures::sync::{Lrc, RwLock, Lock};
|
||||
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
|
|
@ -26,11 +25,11 @@ use std::{cmp, fs};
|
|||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::allocator::{global_allocator_spans, AllocatorKind};
|
||||
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax::{span_err, span_fatal};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use log::{debug, info, log_enabled};
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
|
||||
pub struct Library {
|
||||
pub dylib: Option<(PathBuf, PathKind)>,
|
||||
|
|
@ -230,24 +229,13 @@ impl<'a> CrateLoader<'a> {
|
|||
|
||||
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
|
||||
|
||||
let proc_macros = crate_root.proc_macro_decls_static.map(|_| {
|
||||
let raw_proc_macros = crate_root.proc_macro_data.map(|_| {
|
||||
if self.sess.opts.debugging_opts.dual_proc_macros {
|
||||
let host_lib = host_lib.unwrap();
|
||||
self.load_derive_macros(
|
||||
&host_lib.metadata.get_root(),
|
||||
host_lib.dylib.map(|p| p.0),
|
||||
span
|
||||
)
|
||||
let host_lib = host_lib.as_ref().unwrap();
|
||||
self.dlsym_proc_macros(host_lib.dylib.as_ref().map(|p| p.0.clone()),
|
||||
&host_lib.metadata.get_root(), span)
|
||||
} else {
|
||||
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
|
||||
}
|
||||
});
|
||||
|
||||
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
|
||||
if let Some(proc_macros) = &proc_macros {
|
||||
proc_macro_def_path_table(&crate_root, proc_macros)
|
||||
} else {
|
||||
crate_root.def_path_table.decode((&metadata, self.sess))
|
||||
self.dlsym_proc_macros(dylib.clone().map(|p| p.0), &crate_root, span)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -260,13 +248,16 @@ impl<'a> CrateLoader<'a> {
|
|||
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
|
||||
.collect();
|
||||
|
||||
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
|
||||
crate_root.def_path_table.decode((&metadata, self.sess))
|
||||
});
|
||||
|
||||
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,
|
||||
proc_macros,
|
||||
root: crate_root,
|
||||
blob: metadata,
|
||||
cnum_map,
|
||||
|
|
@ -280,7 +271,10 @@ impl<'a> CrateLoader<'a> {
|
|||
rlib,
|
||||
rmeta,
|
||||
},
|
||||
private_dep
|
||||
private_dep,
|
||||
span,
|
||||
host_lib,
|
||||
raw_proc_macros
|
||||
};
|
||||
|
||||
let cmeta = Lrc::new(cmeta);
|
||||
|
|
@ -389,7 +383,7 @@ impl<'a> CrateLoader<'a> {
|
|||
match result {
|
||||
(LoadResult::Previous(cnum), None) => {
|
||||
let data = self.cstore.get_crate_data(cnum);
|
||||
if data.root.proc_macro_decls_static.is_some() {
|
||||
if data.root.proc_macro_data.is_some() {
|
||||
dep_kind = DepKind::UnexportedMacrosOnly;
|
||||
}
|
||||
data.dep_kind.with_lock(|data_dep_kind| {
|
||||
|
|
@ -482,7 +476,7 @@ impl<'a> CrateLoader<'a> {
|
|||
dep_kind: DepKind)
|
||||
-> cstore::CrateNumMap {
|
||||
debug!("resolving deps of external crate");
|
||||
if crate_root.proc_macro_decls_static.is_some() {
|
||||
if crate_root.proc_macro_data.is_some() {
|
||||
return cstore::CrateNumMap::new();
|
||||
}
|
||||
|
||||
|
|
@ -574,19 +568,13 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads custom derive macros.
|
||||
///
|
||||
/// Note that this is intentionally similar to how we load plugins today,
|
||||
/// but also intentionally separate. Plugins are likely always going to be
|
||||
/// implemented as dynamic libraries, but we have a possible future where
|
||||
/// custom derive (and other macro-1.1 style features) are implemented via
|
||||
/// executables and custom IPC.
|
||||
fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option<PathBuf>, span: Span)
|
||||
-> Vec<(ast::Name, Lrc<SyntaxExtension>)> {
|
||||
use std::{env, mem};
|
||||
fn dlsym_proc_macros(&self,
|
||||
dylib: Option<PathBuf>,
|
||||
root: &CrateRoot<'_>,
|
||||
span: Span
|
||||
) -> &'static [ProcMacro] {
|
||||
use std::env;
|
||||
use crate::dynamic_lib::DynamicLibrary;
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
|
||||
|
||||
let path = match dylib {
|
||||
Some(dylib) => dylib,
|
||||
|
|
@ -608,38 +596,11 @@ impl<'a> CrateLoader<'a> {
|
|||
*(sym as *const &[ProcMacro])
|
||||
};
|
||||
|
||||
let extensions = decls.iter().map(|&decl| {
|
||||
let (name, kind, helper_attrs) = match decl {
|
||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||
let helper_attrs =
|
||||
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
||||
(
|
||||
trait_name,
|
||||
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
|
||||
client, attrs: helper_attrs.clone()
|
||||
})),
|
||||
helper_attrs,
|
||||
)
|
||||
}
|
||||
ProcMacro::Attr { name, client } => (
|
||||
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
|
||||
),
|
||||
ProcMacro::Bang { name, client } => (
|
||||
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
||||
)
|
||||
};
|
||||
|
||||
(Symbol::intern(name), Lrc::new(SyntaxExtension {
|
||||
helper_attrs,
|
||||
..SyntaxExtension::default(kind, root.edition)
|
||||
}))
|
||||
}).collect();
|
||||
|
||||
// Intentionally leak the dynamic library. We can't ever unload it
|
||||
// since the library can make things that will live arbitrarily long.
|
||||
mem::forget(lib);
|
||||
std::mem::forget(lib);
|
||||
|
||||
extensions
|
||||
decls
|
||||
}
|
||||
|
||||
/// Look for a plugin registrar. Returns library path, crate
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub use crate::cstore_impl::{provide, provide_extern};
|
|||
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||
|
||||
pub use rustc_data_structures::sync::MetadataRef;
|
||||
use crate::creader::Library;
|
||||
use syntax_pos::Span;
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
|
||||
pub struct MetadataBlob(pub MetadataRef);
|
||||
|
||||
|
|
@ -82,11 +85,19 @@ pub struct CrateMetadata {
|
|||
pub dep_kind: Lock<DepKind>,
|
||||
pub source: CrateSource,
|
||||
|
||||
pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
|
||||
|
||||
/// Whether or not this crate should be consider a private dependency
|
||||
/// for purposes of the 'exported_private_dependencies' lint
|
||||
pub private_dep: bool
|
||||
pub private_dep: bool,
|
||||
|
||||
pub host_lib: Option<Library>,
|
||||
pub span: Span,
|
||||
|
||||
pub raw_proc_macros: Option<&'static [ProcMacro]>,
|
||||
}
|
||||
|
||||
pub struct FullProcMacro {
|
||||
pub name: ast::Name,
|
||||
pub ext: Lrc<SyntaxExtension>
|
||||
}
|
||||
|
||||
pub struct CStore {
|
||||
|
|
|
|||
|
|
@ -426,8 +426,8 @@ impl cstore::CStore {
|
|||
|
||||
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
|
||||
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());
|
||||
if data.is_proc_macro_crate() {
|
||||
return LoadedMacro::ProcMacro(data.get_proc_macro(id.index, sess).ext);
|
||||
} else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
|
||||
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
||||
let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
|
||||
|
|
@ -439,7 +439,8 @@ impl cstore::CStore {
|
|||
}
|
||||
|
||||
let def = data.get_macro(id.index);
|
||||
let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.imported_name);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
// Decoding metadata from a single crate's metadata
|
||||
|
||||
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
|
||||
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule, FullProcMacro};
|
||||
use crate::schema::*;
|
||||
|
||||
use rustc_data_structures::sync::{Lrc, ReadGuard};
|
||||
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions};
|
||||
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
|
||||
use rustc::hir;
|
||||
use rustc::middle::cstore::LinkagePreference;
|
||||
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
||||
use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc::hir::map::definitions::DefPathTable;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::mir::{self, interpret};
|
||||
|
|
@ -30,10 +29,11 @@ use syntax::attr;
|
|||
use syntax::ast::{self, Ident};
|
||||
use syntax::source_map;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||
use syntax::ext::hygiene::ExpnId;
|
||||
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension};
|
||||
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, symbol::{InternedString}};
|
||||
use log::debug;
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
|
||||
|
||||
pub struct DecodeContext<'a, 'tcx> {
|
||||
opaque: opaque::Decoder<'a>,
|
||||
|
|
@ -138,7 +138,7 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> LazySeq<T> {
|
|||
pub fn decode<M: Metadata<'a, 'tcx>>(
|
||||
self,
|
||||
meta: M,
|
||||
) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
|
||||
) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
|
||||
let mut dcx = meta.decoder(self.position);
|
||||
dcx.lazy_state = LazyState::NodeStart(self.position);
|
||||
(0..self.len).map(move |_| T::decode(&mut dcx).unwrap())
|
||||
|
|
@ -442,46 +442,16 @@ impl<'tcx> EntryKind<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates the "fake" DefPathTable for a given proc macro crate.
|
||||
///
|
||||
/// The DefPathTable is as follows:
|
||||
///
|
||||
/// CRATE_ROOT (DefIndex 0:0)
|
||||
/// |- GlobalMetaDataKind data (DefIndex 1:0 .. DefIndex 1:N)
|
||||
/// |- proc macro #0 (DefIndex 1:N)
|
||||
/// |- proc macro #1 (DefIndex 1:N+1)
|
||||
/// \- ...
|
||||
crate fn proc_macro_def_path_table(crate_root: &CrateRoot<'_>,
|
||||
proc_macros: &[(ast::Name, Lrc<SyntaxExtension>)])
|
||||
-> DefPathTable
|
||||
{
|
||||
let mut definitions = Definitions::default();
|
||||
|
||||
let name = crate_root.name.as_str();
|
||||
let disambiguator = crate_root.disambiguator;
|
||||
debug!("creating proc macro def path table for {:?}/{:?}", name, disambiguator);
|
||||
let crate_root = definitions.create_root_def(&name, disambiguator);
|
||||
for (index, (name, _)) in proc_macros.iter().enumerate() {
|
||||
let def_index = definitions.create_def_with_parent(
|
||||
crate_root,
|
||||
ast::DUMMY_NODE_ID,
|
||||
DefPathData::MacroNs(name.as_interned_str()),
|
||||
ExpnId::root(),
|
||||
DUMMY_SP);
|
||||
debug!("definition for {:?} is {:?}", name, def_index);
|
||||
assert_eq!(def_index, DefIndex::from_proc_macro_index(index));
|
||||
}
|
||||
|
||||
definitions.def_path_table().clone()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CrateMetadata {
|
||||
pub fn is_proc_macro_crate(&self) -> bool {
|
||||
self.root.proc_macro_decls_static.is_some()
|
||||
}
|
||||
fn is_proc_macro(&self, id: DefIndex) -> bool {
|
||||
self.proc_macros.is_some() && id != CRATE_DEF_INDEX
|
||||
self.is_proc_macro_crate() &&
|
||||
self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
|
||||
}
|
||||
|
||||
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
|
||||
assert!(!self.is_proc_macro(item_id));
|
||||
self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
|
||||
}
|
||||
|
||||
|
|
@ -504,13 +474,24 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
|
||||
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
|
||||
// with items in 'raw_proc_macros'
|
||||
let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap();
|
||||
&self.raw_proc_macros.unwrap()[pos]
|
||||
}
|
||||
|
||||
pub fn item_name(&self, item_index: DefIndex) -> Symbol {
|
||||
self.def_key(item_index)
|
||||
.disambiguated_data
|
||||
.data
|
||||
.get_opt_name()
|
||||
.expect("no name in item_name")
|
||||
.as_symbol()
|
||||
if !self.is_proc_macro(item_index) {
|
||||
self.def_key(item_index)
|
||||
.disambiguated_data
|
||||
.data
|
||||
.get_opt_name()
|
||||
.expect("no name in item_name")
|
||||
.as_symbol()
|
||||
} else {
|
||||
Symbol::intern(self.raw_proc_macro(item_index).name())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
|
||||
|
|
@ -518,15 +499,64 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.entry(index).kind.def_kind()
|
||||
} else {
|
||||
Some(DefKind::Macro(
|
||||
self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind()
|
||||
macro_kind(self.raw_proc_macro(index))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
|
||||
match self.is_proc_macro(index) {
|
||||
true => DUMMY_SP,
|
||||
false => self.entry(index).span.decode((self, sess)),
|
||||
self.entry(index).span.decode((self, sess))
|
||||
}
|
||||
|
||||
|
||||
pub fn get_proc_macro(&self, id: DefIndex, sess: &Session) -> FullProcMacro {
|
||||
if sess.opts.debugging_opts.dual_proc_macros {
|
||||
let host_lib = self.host_lib.as_ref().unwrap();
|
||||
self.load_proc_macro(
|
||||
&host_lib.metadata.get_root(),
|
||||
id,
|
||||
sess
|
||||
)
|
||||
} else {
|
||||
self.load_proc_macro(&self.root, id, sess)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_proc_macro(&self, root: &CrateRoot<'_>,
|
||||
id: DefIndex,
|
||||
sess: &Session)
|
||||
-> FullProcMacro {
|
||||
|
||||
let raw_macro = self.raw_proc_macro(id);
|
||||
let (name, kind, helper_attrs) = match *raw_macro {
|
||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||
let helper_attrs =
|
||||
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
||||
(
|
||||
trait_name,
|
||||
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
|
||||
client, attrs: helper_attrs.clone()
|
||||
})),
|
||||
helper_attrs,
|
||||
)
|
||||
}
|
||||
ProcMacro::Attr { name, client } => (
|
||||
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
|
||||
),
|
||||
ProcMacro::Bang { name, client } => (
|
||||
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
||||
)
|
||||
};
|
||||
|
||||
let span = self.get_span(id, sess);
|
||||
|
||||
FullProcMacro {
|
||||
name: Symbol::intern(name),
|
||||
ext: Lrc::new(SyntaxExtension {
|
||||
span,
|
||||
helper_attrs,
|
||||
..SyntaxExtension::default(kind, root.edition)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -723,7 +753,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
/// Iterates over the language items in the given crate.
|
||||
pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not export any lang-items to the target.
|
||||
&[]
|
||||
} else {
|
||||
|
|
@ -738,18 +768,18 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
|
||||
where F: FnMut(def::Export<hir::HirId>)
|
||||
{
|
||||
if let Some(ref proc_macros) = self.proc_macros {
|
||||
if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) {
|
||||
/* If we are loading as a proc macro, we want to return the view of this crate
|
||||
* as a proc macro crate, not as a Rust crate. See `proc_macro_def_path_table`
|
||||
* for the DefPathTable we are corresponding to.
|
||||
* as a proc macro crate.
|
||||
*/
|
||||
if id == CRATE_DEF_INDEX {
|
||||
for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
|
||||
for def_index in proc_macros_ids {
|
||||
let raw_macro = self.raw_proc_macro(def_index);
|
||||
let res = Res::Def(
|
||||
DefKind::Macro(ext.macro_kind()),
|
||||
self.local_def_id(DefIndex::from_proc_macro_index(id)),
|
||||
DefKind::Macro(macro_kind(raw_macro)),
|
||||
self.local_def_id(def_index),
|
||||
);
|
||||
let ident = Ident::with_dummy_span(name);
|
||||
let ident = Ident::from_str(raw_macro.name());
|
||||
callback(def::Export {
|
||||
ident: ident,
|
||||
res: res,
|
||||
|
|
@ -960,11 +990,8 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
|
||||
if self.is_proc_macro(node_id) {
|
||||
return Lrc::new([]);
|
||||
}
|
||||
|
||||
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
|
||||
// The attributes for a tuple struct/variant are attached to the definition, not the ctor;
|
||||
// we assume that someone passing in a tuple struct ctor is actually wanting to
|
||||
// look at the definition
|
||||
|
|
@ -1022,7 +1049,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
filter: Option<DefId>,
|
||||
) -> &'tcx [DefId] {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// proc-macro crates export no trait impls.
|
||||
return &[]
|
||||
}
|
||||
|
|
@ -1066,7 +1093,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
|
||||
pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* native libraries.
|
||||
vec![]
|
||||
} else {
|
||||
|
|
@ -1075,7 +1102,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* foreign modules.
|
||||
&[]
|
||||
} else {
|
||||
|
|
@ -1098,7 +1125,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not depend on any target weak lang-items.
|
||||
&[]
|
||||
} else {
|
||||
|
|
@ -1122,7 +1149,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
|
||||
if self.proc_macros.is_some() {
|
||||
if self.is_proc_macro_crate() {
|
||||
// If this crate is a custom derive crate, then we're not even going to
|
||||
// link those in so we skip those crates.
|
||||
vec![]
|
||||
|
|
@ -1191,13 +1218,18 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
#[inline]
|
||||
pub fn def_key(&self, index: DefIndex) -> DefKey {
|
||||
self.def_path_table.def_key(index)
|
||||
let mut key = self.def_path_table.def_key(index);
|
||||
if self.is_proc_macro(index) {
|
||||
let name = self.raw_proc_macro(index).name();
|
||||
key.disambiguated_data.data = DefPathData::MacroNs(InternedString::intern(name));
|
||||
}
|
||||
key
|
||||
}
|
||||
|
||||
// Returns the path leading to the thing with this `id`.
|
||||
pub fn def_path(&self, id: DefIndex) -> DefPath {
|
||||
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
|
||||
DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent))
|
||||
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1310,3 +1342,13 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.source_map_import_info.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot be implemented on 'ProcMacro', as libproc_macro
|
||||
// does not depend on libsyntax
|
||||
fn macro_kind(raw: &ProcMacro) -> MacroKind {
|
||||
match raw {
|
||||
ProcMacro::CustomDerive { .. } => MacroKind::Derive,
|
||||
ProcMacro::Attr { .. } => MacroKind::Attr,
|
||||
ProcMacro::Bang { .. } => MacroKind::Bang
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use rustc_data_structures::sync::Lrc;
|
|||
use std::u32;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::proc_macro::is_proc_macro_attr;
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::symbol::{kw, sym, Ident};
|
||||
use syntax_pos::{self, FileName, SourceFile, Span};
|
||||
|
|
@ -383,6 +384,8 @@ impl<'tcx> EncodeContext<'tcx> {
|
|||
}
|
||||
|
||||
fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
|
||||
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
|
||||
|
||||
let mut i = self.position();
|
||||
|
||||
let crate_deps = self.encode_crate_deps();
|
||||
|
|
@ -463,16 +466,23 @@ impl<'tcx> EncodeContext<'tcx> {
|
|||
self.lazy_seq(interpret_alloc_index)
|
||||
};
|
||||
|
||||
|
||||
i = self.position();
|
||||
let entries_index = self.entries_index.write_index(&mut self.opaque);
|
||||
let entries_index_bytes = self.position() - i;
|
||||
|
||||
// Encode the proc macro data
|
||||
i = self.position();
|
||||
let proc_macro_data = self.encode_proc_macros();
|
||||
let proc_macro_data_bytes = self.position() - i;
|
||||
|
||||
|
||||
let attrs = tcx.hir().krate_attrs();
|
||||
let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
|
||||
let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
|
||||
let has_global_allocator = *tcx.sess.has_global_allocator.get();
|
||||
let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false);
|
||||
|
||||
|
||||
let root = self.lazy(&CrateRoot {
|
||||
name: tcx.crate_name(LOCAL_CRATE),
|
||||
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
|
||||
|
|
@ -491,6 +501,7 @@ impl<'tcx> EncodeContext<'tcx> {
|
|||
} else {
|
||||
None
|
||||
},
|
||||
proc_macro_data,
|
||||
proc_macro_stability: if is_proc_macro {
|
||||
tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone())
|
||||
} else {
|
||||
|
|
@ -539,6 +550,7 @@ impl<'tcx> EncodeContext<'tcx> {
|
|||
println!(" impl bytes: {}", impl_bytes);
|
||||
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
|
||||
println!(" def-path table bytes: {}", def_path_table_bytes);
|
||||
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
|
||||
println!(" item bytes: {}", item_bytes);
|
||||
println!(" entries index bytes: {}", entries_index_bytes);
|
||||
println!(" zero bytes: {}", zero_bytes);
|
||||
|
|
@ -1470,6 +1482,22 @@ impl EncodeContext<'tcx> {
|
|||
self.lazy_seq(foreign_modules.iter().cloned())
|
||||
}
|
||||
|
||||
fn encode_proc_macros(&mut self) -> Option<LazySeq<DefIndex>> {
|
||||
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
|
||||
if is_proc_macro {
|
||||
let proc_macros: Vec<_> = self.tcx.hir().krate().items.values().filter_map(|item| {
|
||||
if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
|
||||
Some(item.hir_id.owner)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
Some(self.lazy_seq(proc_macros))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
|
||||
let crates = self.tcx.crates();
|
||||
|
||||
|
|
|
|||
|
|
@ -716,7 +716,9 @@ impl<'a> Context<'a> {
|
|||
|
||||
let root = metadata.get_root();
|
||||
if let Some(is_proc_macro) = self.is_proc_macro {
|
||||
if root.proc_macro_decls_static.is_some() != is_proc_macro {
|
||||
if root.proc_macro_data.is_some() != is_proc_macro {
|
||||
info!("Rejecting via proc macro: expected {} got {}",
|
||||
is_proc_macro, root.proc_macro_data.is_some());
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,10 @@ pub struct CrateRoot<'tcx> {
|
|||
|
||||
pub entries_index: LazySeq<index::Index<'tcx>>,
|
||||
|
||||
/// The DefIndex's of any proc macros delcared by
|
||||
/// this crate
|
||||
pub proc_macro_data: Option<LazySeq<DefIndex>>,
|
||||
|
||||
pub compiler_builtins: bool,
|
||||
pub needs_allocator: bool,
|
||||
pub needs_panic_runtime: bool,
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
|
||||
Ok(string) => format!("move {}", string),
|
||||
Ok(mut string) => {
|
||||
if string.starts_with("async ") {
|
||||
string.insert_str(6, "move ");
|
||||
} else if string.starts_with("async|") {
|
||||
string.insert_str(5, " move");
|
||||
} else {
|
||||
string.insert_str(0, "move ");
|
||||
};
|
||||
string
|
||||
},
|
||||
Err(_) => "move |<args>| <body>".to_string()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -578,7 +578,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
hir::LifetimeName::Implicit => {
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| hir::LifetimeName::Implicit => {
|
||||
// In this case, the user left off the lifetime; so
|
||||
// they wrote something like:
|
||||
//
|
||||
|
|
|
|||
|
|
@ -657,6 +657,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
|
||||
}
|
||||
}
|
||||
PatternKind::Or { ref pats } => {
|
||||
for pat in pats {
|
||||
self.visit_bindings(&pat, pattern_user_ty.clone(), f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,6 +195,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
candidate.match_pairs.push(MatchPair::new(place, subpattern));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Or { .. } => {
|
||||
Err(match_pair)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Array { .. } |
|
||||
PatternKind::Wild |
|
||||
PatternKind::Or { .. } |
|
||||
PatternKind::Binding { .. } |
|
||||
PatternKind::Leaf { .. } |
|
||||
PatternKind::Deref { .. } => {
|
||||
|
|
@ -130,6 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
PatternKind::Slice { .. } |
|
||||
PatternKind::Array { .. } |
|
||||
PatternKind::Wild |
|
||||
PatternKind::Or { .. } |
|
||||
PatternKind::Binding { .. } |
|
||||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Leaf { .. } |
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ use rustc::hir::def::DefKind;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
|
||||
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
|
|
@ -415,7 +414,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
_bin_op: mir::BinOp,
|
||||
_left: ImmTy<'tcx>,
|
||||
_right: ImmTy<'tcx>,
|
||||
) -> InterpResult<'tcx, (Scalar, bool)> {
|
||||
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
|
||||
Err(
|
||||
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1359,6 +1359,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
|||
Some(vec![Slice(pat_len)])
|
||||
}
|
||||
}
|
||||
PatternKind::Or { .. } => {
|
||||
bug!("support for or-patterns has not been fully implemented yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1884,6 +1887,10 @@ fn specialize<'p, 'a: 'p, 'tcx>(
|
|||
"unexpected ctor {:?} for slice pat", constructor)
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Or { .. } => {
|
||||
bug!("support for or-patterns has not been fully implemented yet.");
|
||||
}
|
||||
};
|
||||
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,12 @@ pub enum PatternKind<'tcx> {
|
|||
slice: Option<Pattern<'tcx>>,
|
||||
suffix: Vec<Pattern<'tcx>>,
|
||||
},
|
||||
|
||||
/// An or-pattern, e.g. `p | q`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
Or {
|
||||
pats: Vec<Pattern<'tcx>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
|
|
@ -186,6 +192,18 @@ pub struct PatternRange<'tcx> {
|
|||
|
||||
impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Printing lists is a chore.
|
||||
let mut first = true;
|
||||
let mut start_or_continue = |s| {
|
||||
if first {
|
||||
first = false;
|
||||
""
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let mut start_or_comma = || start_or_continue(", ");
|
||||
|
||||
match *self.kind {
|
||||
PatternKind::Wild => write!(f, "_"),
|
||||
PatternKind::AscribeUserType { ref subpattern, .. } =>
|
||||
|
|
@ -224,9 +242,6 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let mut first = true;
|
||||
let mut start_or_continue = || if first { first = false; "" } else { ", " };
|
||||
|
||||
if let Some(variant) = variant {
|
||||
write!(f, "{}", variant.ident)?;
|
||||
|
||||
|
|
@ -241,12 +256,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
continue;
|
||||
}
|
||||
let name = variant.fields[p.field.index()].ident;
|
||||
write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
|
||||
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
if printed < variant.fields.len() {
|
||||
write!(f, "{}..", start_or_continue())?;
|
||||
write!(f, "{}..", start_or_comma())?;
|
||||
}
|
||||
|
||||
return write!(f, " }}");
|
||||
|
|
@ -257,7 +272,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
if num_fields != 0 || variant.is_none() {
|
||||
write!(f, "(")?;
|
||||
for i in 0..num_fields {
|
||||
write!(f, "{}", start_or_continue())?;
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
|
||||
// Common case: the field is where we expect it.
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
|
|
@ -305,14 +320,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
}
|
||||
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
let mut first = true;
|
||||
let mut start_or_continue = || if first { first = false; "" } else { ", " };
|
||||
write!(f, "[")?;
|
||||
for p in prefix {
|
||||
write!(f, "{}{}", start_or_continue(), p)?;
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
write!(f, "{}", start_or_continue())?;
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
match *slice.kind {
|
||||
PatternKind::Wild => {}
|
||||
_ => write!(f, "{}", slice)?
|
||||
|
|
@ -320,10 +333,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
write!(f, "..")?;
|
||||
}
|
||||
for p in suffix {
|
||||
write!(f, "{}{}", start_or_continue(), p)?;
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
PatternKind::Or { ref pats } => {
|
||||
for pat in pats {
|
||||
write!(f, "{}{}", start_or_continue(" | "), pat)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -655,6 +674,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
|
||||
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
PatternKind::Or {
|
||||
pats: pats.iter().map(|p| self.lower_pattern(p)).collect(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Pattern {
|
||||
|
|
@ -1436,6 +1461,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
|||
slice: slice.fold_with(folder),
|
||||
suffix: suffix.fold_with(folder)
|
||||
},
|
||||
PatternKind::Or { ref pats } => PatternKind::Or { pats: pats.fold_with(folder) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc::ty::{self, Ty, TypeAndMut};
|
||||
use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
|
||||
use rustc::ty::layout::{self, TyLayout, Size};
|
||||
use rustc::ty::adjustment::{PointerCast};
|
||||
use syntax::ast::FloatTy;
|
||||
|
|
@ -36,15 +36,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// The src operand does not matter, just its type
|
||||
match src.layout.ty.sty {
|
||||
ty::FnDef(def_id, substs) => {
|
||||
// All reifications must be monomorphic, bail out otherwise.
|
||||
if src.layout.ty.needs_subst() {
|
||||
throw_inval!(TooGeneric);
|
||||
}
|
||||
|
||||
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
|
||||
bug!("reifying a fn ptr that requires const arguments");
|
||||
}
|
||||
let instance = ty::Instance::resolve(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
).ok_or_else(|| err_inval!(TooGeneric))?;
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
|
||||
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
|
||||
}
|
||||
|
|
@ -67,7 +67,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// The src operand does not matter, just its type
|
||||
match src.layout.ty.sty {
|
||||
ty::Closure(def_id, substs) => {
|
||||
let substs = self.subst_and_normalize_erasing_regions(substs)?;
|
||||
// All reifications must be monomorphic, bail out otherwise.
|
||||
if src.layout.ty.needs_subst() {
|
||||
throw_inval!(TooGeneric);
|
||||
}
|
||||
|
||||
let instance = ty::Instance::resolve_closure(
|
||||
*self.tcx,
|
||||
def_id,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc::mir;
|
|||
use rustc::ty::layout::{
|
||||
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
|
||||
};
|
||||
use rustc::ty::subst::{Subst, SubstsRef};
|
||||
use rustc::ty::subst::SubstsRef;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::query::TyCtxtAt;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
|
|
@ -291,41 +291,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
substs: T,
|
||||
) -> InterpResult<'tcx, T> {
|
||||
match self.stack.last() {
|
||||
Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions(
|
||||
frame.instance.substs,
|
||||
self.param_env,
|
||||
&substs,
|
||||
)),
|
||||
None => if substs.needs_subst() {
|
||||
throw_inval!(TooGeneric)
|
||||
} else {
|
||||
Ok(substs)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>
|
||||
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
|
||||
trace!("resolve: {:?}, {:#?}", def_id, substs);
|
||||
trace!("param_env: {:#?}", self.param_env);
|
||||
let substs = self.subst_and_normalize_erasing_regions(substs)?;
|
||||
trace!("substs: {:#?}", substs);
|
||||
ty::Instance::resolve(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
).ok_or_else(|| err_inval!(TooGeneric).into())
|
||||
}
|
||||
|
||||
pub fn load_mir(
|
||||
&self,
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
|
|
@ -349,34 +314,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
|
||||
/// Call this on things you got out of the MIR (so it is as generic as the current
|
||||
/// stack frame), to bring it into the proper environment for this interpreter.
|
||||
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
t: T,
|
||||
) -> InterpResult<'tcx, T> {
|
||||
match self.stack.last() {
|
||||
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
|
||||
None => if t.needs_subst() {
|
||||
throw_inval!(TooGeneric)
|
||||
} else {
|
||||
Ok(t)
|
||||
},
|
||||
}
|
||||
value: T,
|
||||
) -> T {
|
||||
self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.frame().instance.substs,
|
||||
self.param_env,
|
||||
&value,
|
||||
)
|
||||
}
|
||||
|
||||
fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>(
|
||||
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
||||
pub(super) fn resolve(
|
||||
&self,
|
||||
t: T,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>
|
||||
) -> InterpResult<'tcx, T> {
|
||||
// miri doesn't care about lifetimes, and will choke on some crazy ones
|
||||
// let's simply get rid of them
|
||||
let substituted = t.subst(*self.tcx, substs);
|
||||
|
||||
if substituted.needs_subst() {
|
||||
throw_inval!(TooGeneric)
|
||||
}
|
||||
|
||||
Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
|
||||
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
|
||||
trace!("resolve: {:?}, {:#?}", def_id, substs);
|
||||
trace!("param_env: {:#?}", self.param_env);
|
||||
trace!("substs: {:#?}", substs);
|
||||
ty::Instance::resolve(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
).ok_or_else(|| err_inval!(TooGeneric).into())
|
||||
}
|
||||
|
||||
pub fn layout_of_local(
|
||||
|
|
@ -391,7 +356,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
None => {
|
||||
let layout = crate::interpret::operand::from_known_layout(layout, || {
|
||||
let local_ty = frame.body.local_decls[local].ty;
|
||||
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
|
||||
let local_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
frame.instance.substs,
|
||||
self.param_env,
|
||||
&local_ty,
|
||||
);
|
||||
self.layout_of(local_ty)
|
||||
})?;
|
||||
if let Some(state) = frame.locals.get(local) {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let l = self.read_immediate(args[0])?;
|
||||
let r = self.read_immediate(args[1])?;
|
||||
let is_add = intrinsic_name == "saturating_add";
|
||||
let (val, overflowed) = self.binary_op(if is_add {
|
||||
let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
|
||||
BinOp::Add
|
||||
} else {
|
||||
BinOp::Sub
|
||||
|
|
@ -184,7 +184,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
"unchecked_shr" => BinOp::Shr,
|
||||
_ => bug!("Already checked for int ops")
|
||||
};
|
||||
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
|
||||
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
|
||||
if overflowed {
|
||||
let layout = self.layout_of(substs.type_at(0))?;
|
||||
let r_val = r.to_scalar()?.to_bits(layout.size)?;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::hash::Hash;
|
|||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
|
||||
use super::{
|
||||
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
|
||||
|
|
@ -176,7 +176,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
bin_op: mir::BinOp,
|
||||
left: ImmTy<'tcx, Self::PointerTag>,
|
||||
right: ImmTy<'tcx, Self::PointerTag>,
|
||||
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
|
||||
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
|
||||
|
||||
/// Heap allocations via the `box` keyword.
|
||||
fn box_alloc(
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
/// and `align`. On success, returns `None` for zero-sized accesses (where
|
||||
/// nothing else is left to do) and a `Pointer` to use for the actual access otherwise.
|
||||
/// Crucially, if the input is a `Pointer`, we will test it for liveness
|
||||
/// *even of* the size is 0.
|
||||
/// *even if* the size is 0.
|
||||
///
|
||||
/// Everyone accessing memory based on a `Scalar` should use this method to get the
|
||||
/// `Pointer` they need. And even if you already have a `Pointer`, call this method
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ impl<'tcx, Tag> Immediate<Tag> {
|
|||
// as input for binary and cast operations.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ImmTy<'tcx, Tag=()> {
|
||||
pub imm: Immediate<Tag>,
|
||||
pub(crate) imm: Immediate<Tag>,
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ impl<Tag> Operand<Tag> {
|
|||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct OpTy<'tcx, Tag=()> {
|
||||
op: Operand<Tag>,
|
||||
op: Operand<Tag>, // Keep this private, it helps enforce invariants
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -187,13 +187,22 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
|
||||
{
|
||||
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> {
|
||||
#[inline]
|
||||
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
|
||||
ImmTy { imm: val.into(), layout }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_uint(i: impl Into<u128>, layout: TyLayout<'tcx>) -> Self {
|
||||
Self::from_scalar(Scalar::from_uint(i, layout.size), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_int(i: impl Into<i128>, layout: TyLayout<'tcx>) -> Self {
|
||||
Self::from_scalar(Scalar::from_int(i, layout.size), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_bits(self) -> InterpResult<'tcx, u128> {
|
||||
self.to_scalar()?.to_bits(self.layout.size)
|
||||
|
|
@ -513,7 +522,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Move(ref place) =>
|
||||
self.eval_place_to_op(place, layout)?,
|
||||
|
||||
Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?,
|
||||
Constant(ref constant) => {
|
||||
let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal);
|
||||
self.eval_const_to_op(val, layout)?
|
||||
}
|
||||
};
|
||||
trace!("{:?}: {:?}", mir_op, *op);
|
||||
Ok(op)
|
||||
|
|
@ -531,6 +543,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
// Used when the miri-engine runs into a constant and for extracting information from constants
|
||||
// in patterns via the `const_eval` module
|
||||
/// The `val` and `layout` are assumed to already be in our interpreter
|
||||
/// "universe" (param_env).
|
||||
crate fn eval_const_to_op(
|
||||
&self,
|
||||
val: &'tcx ty::Const<'tcx>,
|
||||
|
|
@ -543,7 +557,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Early-return cases.
|
||||
match val.val {
|
||||
ConstValue::Param(_) =>
|
||||
// FIXME(oli-obk): try to monomorphize
|
||||
throw_inval!(TooGeneric),
|
||||
ConstValue::Unevaluated(def_id, substs) => {
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
|
|
@ -556,7 +569,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
// Other cases need layout.
|
||||
let layout = from_known_layout(layout, || {
|
||||
self.layout_of(self.monomorphize(val.ty)?)
|
||||
self.layout_of(val.ty)
|
||||
})?;
|
||||
let op = match val.val {
|
||||
ConstValue::ByRef { alloc, offset } => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc::mir;
|
||||
use rustc::ty::{self, layout::TyLayout};
|
||||
use rustc::ty::{self, Ty, layout::{TyLayout, LayoutOf}};
|
||||
use syntax::ast::FloatTy;
|
||||
use rustc_apfloat::Float;
|
||||
use rustc::mir::interpret::{InterpResult, Scalar};
|
||||
|
|
@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (val, overflowed) = self.binary_op(op, left, right)?;
|
||||
let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
|
||||
debug_assert_eq!(
|
||||
self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
|
||||
dest.layout.ty,
|
||||
"type mismatch for result of {:?}", op,
|
||||
);
|
||||
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
||||
self.write_immediate(val, dest)
|
||||
}
|
||||
|
|
@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (val, _overflowed) = self.binary_op(op, left, right)?;
|
||||
let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
|
||||
assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
|
||||
self.write_scalar(val, dest)
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
bin_op: mir::BinOp,
|
||||
l: char,
|
||||
r: char,
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
|
|
@ -54,7 +60,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Ge => l >= r,
|
||||
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
||||
};
|
||||
return (Scalar::from_bool(res), false);
|
||||
return (Scalar::from_bool(res), false, self.tcx.types.bool);
|
||||
}
|
||||
|
||||
fn binary_bool_op(
|
||||
|
|
@ -62,7 +68,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
bin_op: mir::BinOp,
|
||||
l: bool,
|
||||
r: bool,
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
|
|
@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
BitXor => l ^ r,
|
||||
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
||||
};
|
||||
return (Scalar::from_bool(res), false);
|
||||
return (Scalar::from_bool(res), false, self.tcx.types.bool);
|
||||
}
|
||||
|
||||
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
ty: Ty<'tcx>,
|
||||
l: F,
|
||||
r: F,
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let val = match bin_op {
|
||||
Eq => Scalar::from_bool(l == r),
|
||||
Ne => Scalar::from_bool(l != r),
|
||||
Lt => Scalar::from_bool(l < r),
|
||||
Le => Scalar::from_bool(l <= r),
|
||||
Gt => Scalar::from_bool(l > r),
|
||||
Ge => Scalar::from_bool(l >= r),
|
||||
Add => (l + r).value.into(),
|
||||
Sub => (l - r).value.into(),
|
||||
Mul => (l * r).value.into(),
|
||||
Div => (l / r).value.into(),
|
||||
Rem => (l % r).value.into(),
|
||||
let (val, ty) = match bin_op {
|
||||
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||
Add => ((l + r).value.into(), ty),
|
||||
Sub => ((l - r).value.into(), ty),
|
||||
Mul => ((l * r).value.into(), ty),
|
||||
Div => ((l / r).value.into(), ty),
|
||||
Rem => ((l % r).value.into(), ty),
|
||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
return (val, false);
|
||||
return (val, false, ty);
|
||||
}
|
||||
|
||||
fn binary_int_op(
|
||||
|
|
@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
left_layout: TyLayout<'tcx>,
|
||||
r: u128,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
// Shift ops can have an RHS with a different numeric type.
|
||||
|
|
@ -142,7 +149,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo));
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||
}
|
||||
|
||||
// For the remaining ops, the types must be the same on both sides
|
||||
|
|
@ -167,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
if let Some(op) = op {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let r = self.sign_extend(r, right_layout) as i128;
|
||||
return Ok((Scalar::from_bool(op(&l, &r)), false));
|
||||
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
|
||||
}
|
||||
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
||||
Div if r == 0 => throw_panic!(DivisionByZero),
|
||||
|
|
@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Rem | Div => {
|
||||
// int_min / -1
|
||||
if r == -1 && l == (1 << (size.bits() - 1)) {
|
||||
return Ok((Scalar::from_uint(l, size), true));
|
||||
return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
|
@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// this may be out-of-bounds for the result type, so we have to truncate ourselves
|
||||
let result = result as u128;
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo));
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||
}
|
||||
}
|
||||
|
||||
let size = left_layout.size;
|
||||
|
||||
// only ints left
|
||||
let val = match bin_op {
|
||||
Eq => Scalar::from_bool(l == r),
|
||||
Ne => Scalar::from_bool(l != r),
|
||||
let (val, ty) = match bin_op {
|
||||
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||
|
||||
Lt => Scalar::from_bool(l < r),
|
||||
Le => Scalar::from_bool(l <= r),
|
||||
Gt => Scalar::from_bool(l > r),
|
||||
Ge => Scalar::from_bool(l >= r),
|
||||
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||
|
||||
BitOr => Scalar::from_uint(l | r, size),
|
||||
BitAnd => Scalar::from_uint(l & r, size),
|
||||
BitXor => Scalar::from_uint(l ^ r, size),
|
||||
BitOr => (Scalar::from_uint(l | r, size), left_layout.ty),
|
||||
BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
|
||||
BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
|
||||
|
||||
Add | Sub | Mul | Rem | Div => {
|
||||
debug_assert!(!left_layout.abi.is_signed());
|
||||
|
|
@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
};
|
||||
let (result, oflo) = op(l, r);
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
|
||||
return Ok((
|
||||
Scalar::from_uint(truncated, size),
|
||||
oflo || truncated != result,
|
||||
left_layout.ty,
|
||||
));
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
@ -250,17 +260,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
|
||||
Ok((val, false))
|
||||
Ok((val, false, ty))
|
||||
}
|
||||
|
||||
/// Returns the result of the specified operation and whether it overflowed.
|
||||
#[inline]
|
||||
pub fn binary_op(
|
||||
/// Returns the result of the specified operation, whether it overflowed, and
|
||||
/// the result type.
|
||||
pub fn overflowing_binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: ImmTy<'tcx, M::PointerTag>,
|
||||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op, *left, left.layout.ty, *right, right.layout.ty);
|
||||
|
||||
|
|
@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
ty::Float(fty) => {
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let ty = left.layout.ty;
|
||||
let left = left.to_scalar()?;
|
||||
let right = right.to_scalar()?;
|
||||
Ok(match fty {
|
||||
FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?),
|
||||
FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?),
|
||||
FloatTy::F32 =>
|
||||
self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?),
|
||||
FloatTy::F64 =>
|
||||
self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?),
|
||||
})
|
||||
}
|
||||
_ if left.layout.ty.is_integral() => {
|
||||
|
|
@ -312,11 +325,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
|
||||
#[inline]
|
||||
pub fn binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: ImmTy<'tcx, M::PointerTag>,
|
||||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||
let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
|
||||
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||
}
|
||||
|
||||
pub fn unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||
use rustc::mir::UnOp::*;
|
||||
|
||||
let layout = val.layout;
|
||||
|
|
@ -330,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Not => !val,
|
||||
_ => bug!("Invalid bool op {:?}", un_op)
|
||||
};
|
||||
Ok(Scalar::from_bool(res))
|
||||
Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
let res = match (un_op, fty) {
|
||||
|
|
@ -338,7 +363,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||
_ => bug!("Invalid float op {:?}", un_op)
|
||||
};
|
||||
Ok(res)
|
||||
Ok(ImmTy::from_scalar(res, layout))
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
|
|
@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
// res needs tuncating
|
||||
Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
|
||||
Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ pub enum Place<Tag=(), Id=AllocId> {
|
|||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PlaceTy<'tcx, Tag=()> {
|
||||
place: Place<Tag>,
|
||||
place: Place<Tag>, // Keep this private, it helps enforce invariants
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -640,8 +640,11 @@ where
|
|||
// their layout on return.
|
||||
PlaceTy {
|
||||
place: *return_place,
|
||||
layout: self
|
||||
.layout_of(self.monomorphize(self.frame().body.return_ty())?)?,
|
||||
layout: self.layout_of(
|
||||
self.subst_from_frame_and_normalize_erasing_regions(
|
||||
self.frame().body.return_ty()
|
||||
)
|
||||
)?,
|
||||
}
|
||||
}
|
||||
None => throw_unsup!(InvalidNullPointerUsage),
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// The operand always has the same type as the result.
|
||||
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
|
||||
let val = self.unary_op(un_op, val)?;
|
||||
self.write_scalar(val, dest)?;
|
||||
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
|
||||
self.write_immediate(*val, dest)?;
|
||||
}
|
||||
|
||||
Aggregate(ref kind, ref operands) => {
|
||||
|
|
@ -253,7 +254,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
let ty = self.monomorphize(ty)?;
|
||||
let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
|
||||
let layout = self.layout_of(ty)?;
|
||||
assert!(!layout.is_unsized(),
|
||||
"SizeOf nullary MIR operator called for unsized type");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use syntax::source_map::Span;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use super::{
|
||||
InterpResult, PointerArithmetic, Scalar,
|
||||
InterpResult, PointerArithmetic,
|
||||
InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
|
||||
};
|
||||
|
||||
|
|
@ -50,11 +50,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
for (index, &const_int) in values.iter().enumerate() {
|
||||
// Compare using binary_op, to also support pointer values
|
||||
let const_int = Scalar::from_uint(const_int, discr.layout.size);
|
||||
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
||||
let res = self.overflowing_binary_op(mir::BinOp::Eq,
|
||||
discr,
|
||||
ImmTy::from_scalar(const_int, discr.layout),
|
||||
)?;
|
||||
ImmTy::from_uint(const_int, discr.layout),
|
||||
)?.0;
|
||||
if res.to_bool()? {
|
||||
target_block = targets[index];
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc::ty::{self, Ty, Instance};
|
||||
use rustc::ty::{self, Ty, Instance, TypeFoldable};
|
||||
use rustc::ty::layout::{Size, Align, LayoutOf};
|
||||
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
|
||||
|
||||
|
|
@ -20,6 +20,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
|
||||
|
||||
// All vtables must be monomorphic, bail out otherwise.
|
||||
if ty.needs_subst() || poly_trait_ref.needs_subst() {
|
||||
throw_inval!(TooGeneric);
|
||||
}
|
||||
|
||||
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
|
||||
// This means we guarantee that there are no duplicate vtables, we will
|
||||
// always use the same vtable for the same (Type, Trait) combination.
|
||||
|
|
@ -77,7 +82,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
for (i, method) in methods.iter().enumerate() {
|
||||
if let Some((def_id, substs)) = *method {
|
||||
// resolve for vtable: insert shims where needed
|
||||
let substs = self.subst_and_normalize_erasing_regions(substs)?;
|
||||
let instance = ty::Instance::resolve_for_vtable(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ fn build_call_shim<'tcx>(
|
|||
Adjustment::DerefMove => {
|
||||
// fn(Self, ...) -> fn(*mut Self, ...)
|
||||
let arg_ty = local_decls[rcvr_arg].ty;
|
||||
assert!(arg_ty.is_self());
|
||||
debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param);
|
||||
local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
|
||||
|
||||
Operand::Move(rcvr_l.deref())
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use syntax_pos::{Span, DUMMY_SP};
|
|||
use rustc::ty::subst::InternalSubsts;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc::ty::layout::{
|
||||
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
|
||||
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout,
|
||||
};
|
||||
|
||||
use crate::interpret::{
|
||||
|
|
@ -396,17 +396,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
if let ty::Slice(_) = mplace.layout.ty.sty {
|
||||
let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
|
||||
|
||||
Some(ImmTy {
|
||||
imm: Immediate::Scalar(
|
||||
Scalar::from_uint(
|
||||
len,
|
||||
Size::from_bits(
|
||||
self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
|
||||
)
|
||||
).into(),
|
||||
),
|
||||
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||
}.into())
|
||||
Some(ImmTy::from_uint(
|
||||
len,
|
||||
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||
).into())
|
||||
} else {
|
||||
trace!("not slice: {:?}", mplace.layout.ty.sty);
|
||||
None
|
||||
|
|
@ -414,12 +407,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
},
|
||||
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
|
||||
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
|
||||
ImmTy {
|
||||
imm: Immediate::Scalar(
|
||||
Scalar::from_uint(n, self.tcx.data_layout.pointer_size).into()
|
||||
),
|
||||
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||
}.into()
|
||||
ImmTy::from_uint(
|
||||
n,
|
||||
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||
).into()
|
||||
))
|
||||
}
|
||||
Rvalue::UnaryOp(op, ref arg) => {
|
||||
|
|
@ -452,11 +443,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// Now run the actual operation.
|
||||
this.ecx.unary_op(op, prim)
|
||||
})?;
|
||||
let res = ImmTy {
|
||||
imm: Immediate::Scalar(val.into()),
|
||||
layout: place_layout,
|
||||
};
|
||||
Some(res.into())
|
||||
Some(val.into())
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||
|
|
@ -510,8 +497,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
this.ecx.read_immediate(left)
|
||||
})?;
|
||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||
let (val, overflow) = self.use_ecx(source_info, |this| {
|
||||
this.ecx.binary_op(op, l, r)
|
||||
let (val, overflow, _ty) = self.use_ecx(source_info, |this| {
|
||||
this.ecx.overflowing_binary_op(op, l, r)
|
||||
})?;
|
||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||
Immediate::ScalarPair(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc::ty::TyCtxt;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir::{self, Node, Destination};
|
||||
use rustc::hir::{self, Node, Destination, GeneratorMovability};
|
||||
use syntax::struct_span_err;
|
||||
use syntax_pos::Span;
|
||||
use errors::Applicability;
|
||||
|
|
@ -17,6 +17,7 @@ enum Context {
|
|||
Normal,
|
||||
Loop(hir::LoopSource),
|
||||
Closure,
|
||||
AsyncClosure,
|
||||
LabeledBlock,
|
||||
AnonConst,
|
||||
}
|
||||
|
|
@ -57,9 +58,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
hir::ExprKind::Loop(ref b, _, source) => {
|
||||
self.with_context(Loop(source), |v| v.visit_block(&b));
|
||||
}
|
||||
hir::ExprKind::Closure(_, ref function_decl, b, _, _) => {
|
||||
hir::ExprKind::Closure(_, ref function_decl, b, _, movability) => {
|
||||
let cx = if let Some(GeneratorMovability::Static) = movability {
|
||||
AsyncClosure
|
||||
} else {
|
||||
Closure
|
||||
};
|
||||
self.visit_fn_decl(&function_decl);
|
||||
self.with_context(Closure, |v| v.visit_nested_body(b));
|
||||
self.with_context(cx, |v| v.visit_nested_body(b));
|
||||
}
|
||||
hir::ExprKind::Block(ref b, Some(_label)) => {
|
||||
self.with_context(LabeledBlock, |v| v.visit_block(&b));
|
||||
|
|
@ -171,6 +177,11 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
.span_label(span, "cannot break inside of a closure")
|
||||
.emit();
|
||||
}
|
||||
AsyncClosure => {
|
||||
struct_span_err!(self.sess, span, E0267, "`{}` inside of an async block", name)
|
||||
.span_label(span, "cannot break inside of an async block")
|
||||
.emit();
|
||||
}
|
||||
Normal | AnonConst => {
|
||||
struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
|
||||
.span_label(span, "cannot break outside of a loop")
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_plugin"
|
||||
name = "rustc_plugin_impl"
|
||||
version = "0.0.0"
|
||||
build = false
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "rustc_plugin"
|
||||
name = "rustc_plugin_impl"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
|
|
|
|||
14
src/librustc_plugin/deprecated/Cargo.toml
Normal file
14
src/librustc_plugin/deprecated/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_plugin"
|
||||
version = "0.0.0"
|
||||
build = false
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "rustc_plugin"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_plugin_impl = { path = ".." }
|
||||
8
src/librustc_plugin/deprecated/lib.rs
Normal file
8
src/librustc_plugin/deprecated/lib.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![feature(staged_api)]
|
||||
#![unstable(feature = "rustc_plugin", issue = "29597")]
|
||||
#![rustc_deprecated(since = "1.38.0", reason = "\
|
||||
import this through `rustc_driver::plugin` instead to make TLS work correctly. \
|
||||
See https://github.com/rust-lang/rust/issues/62717")]
|
||||
|
||||
pub use rustc_plugin_impl::*;
|
||||
|
|
@ -16,12 +16,11 @@
|
|||
//! #![feature(plugin_registrar)]
|
||||
//! #![feature(rustc_private)]
|
||||
//!
|
||||
//! extern crate rustc_plugin;
|
||||
//! extern crate rustc_driver;
|
||||
//! extern crate syntax;
|
||||
//! extern crate syntax_pos;
|
||||
//!
|
||||
//! use rustc_plugin::Registry;
|
||||
//! use rustc_driver::plugin::Registry;
|
||||
//! use syntax::ext::base::{ExtCtxt, MacResult};
|
||||
//! use syntax_pos::Span;
|
||||
//! use syntax::tokenstream::TokenTree;
|
||||
|
|
|
|||
|
|
@ -160,12 +160,25 @@ impl<'a> Resolver<'a> {
|
|||
Some(ext)
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
crate fn build_reduced_graph(
|
||||
&mut self, fragment: &AstFragment, parent_scope: ParentScope<'a>
|
||||
&mut self,
|
||||
fragment: &AstFragment,
|
||||
extra_placeholders: &[NodeId],
|
||||
parent_scope: ParentScope<'a>,
|
||||
) -> LegacyScope<'a> {
|
||||
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, parent_scope.expansion));
|
||||
let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
|
||||
fragment.visit_with(&mut def_collector);
|
||||
for placeholder in extra_placeholders {
|
||||
def_collector.visit_macro_invoc(*placeholder);
|
||||
}
|
||||
|
||||
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
|
||||
fragment.visit_with(&mut visitor);
|
||||
for placeholder in extra_placeholders {
|
||||
visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
|
||||
}
|
||||
|
||||
visitor.parent_scope.legacy
|
||||
}
|
||||
|
||||
|
|
@ -871,7 +884,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
}
|
||||
|
||||
/// Builds the reduced graph for a single item in an external crate.
|
||||
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::NodeId>) {
|
||||
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
|
||||
let parent = self.parent_scope.module;
|
||||
let Export { ident, res, vis, span } = child;
|
||||
// FIXME: We shouldn't create the gensym here, it should come from metadata,
|
||||
|
|
@ -1060,10 +1073,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
false
|
||||
}
|
||||
|
||||
fn visit_invoc(&mut self, id: ast::NodeId) -> LegacyScope<'a> {
|
||||
fn visit_invoc(&mut self, id: NodeId) -> LegacyScope<'a> {
|
||||
let invoc_id = id.placeholder_to_expn_id();
|
||||
|
||||
self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
|
||||
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
|
||||
|
||||
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
|
||||
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ pub struct ModuleData<'a> {
|
|||
populate_on_access: Cell<bool>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
unresolved_invocations: RefCell<FxHashSet<ExpnId>>,
|
||||
unexpanded_invocations: RefCell<FxHashSet<ExpnId>>,
|
||||
|
||||
no_implicit_prelude: bool,
|
||||
|
||||
|
|
@ -478,7 +478,7 @@ impl<'a> ModuleData<'a> {
|
|||
normal_ancestor_id,
|
||||
lazy_resolutions: Default::default(),
|
||||
populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
|
||||
unresolved_invocations: Default::default(),
|
||||
unexpanded_invocations: Default::default(),
|
||||
no_implicit_prelude: false,
|
||||
glob_importers: RefCell::new(Vec::new()),
|
||||
globs: RefCell::new(Vec::new()),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::resolve_imports::ImportResolver;
|
|||
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
|
||||
use rustc::middle::stability;
|
||||
use rustc::{ty, lint, span_bug};
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::ast::{self, NodeId, Ident};
|
||||
use syntax::attr::StabilityLevel;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
|
||||
|
|
@ -26,7 +26,7 @@ use syntax_pos::{Span, DUMMY_SP};
|
|||
use std::{mem, ptr};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
type Res = def::Res<ast::NodeId>;
|
||||
type Res = def::Res<NodeId>;
|
||||
|
||||
/// Binding produced by a `macro_rules` item.
|
||||
/// Not modularized, can shadow previous legacy bindings, etc.
|
||||
|
|
@ -91,11 +91,11 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
|
|||
}
|
||||
|
||||
impl<'a> base::Resolver for Resolver<'a> {
|
||||
fn next_node_id(&mut self) -> ast::NodeId {
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
self.session.next_node_id()
|
||||
}
|
||||
|
||||
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId {
|
||||
fn get_module_scope(&mut self, id: NodeId) -> ExpnId {
|
||||
let expn_id = ExpnId::fresh(Some(ExpnData::default(
|
||||
ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
|
||||
)));
|
||||
|
|
@ -115,23 +115,18 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
fn visit_ast_fragment_with_placeholders(
|
||||
&mut self, expansion: ExpnId, fragment: &AstFragment, derives: &[ExpnId]
|
||||
&mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
|
||||
) {
|
||||
// Fill in some data for derives if the fragment is from a derive container.
|
||||
// Integrate the new AST fragment into all the definition and module structures.
|
||||
// We are inside the `expansion` now, but other parent scope components are still the same.
|
||||
let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
|
||||
let parent_def = self.definitions.invocation_parent(expansion);
|
||||
self.invocation_parent_scopes.extend(derives.iter().map(|&derive| (derive, parent_scope)));
|
||||
for &derive_invoc_id in derives {
|
||||
self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
|
||||
}
|
||||
parent_scope.module.unresolved_invocations.borrow_mut().remove(&expansion);
|
||||
parent_scope.module.unresolved_invocations.borrow_mut().extend(derives);
|
||||
|
||||
// Integrate the new AST fragment into all the definition and module structures.
|
||||
let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
|
||||
let output_legacy_scope =
|
||||
self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
|
||||
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
|
||||
|
||||
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
|
||||
}
|
||||
|
||||
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
|
||||
|
|
@ -485,7 +480,7 @@ impl<'a> Resolver<'a> {
|
|||
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
|
||||
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
|
||||
None => Err(Determinacy::determined(
|
||||
this.graph_root.unresolved_invocations.borrow().is_empty()
|
||||
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
||||
))
|
||||
}
|
||||
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
|
||||
|
|
@ -508,7 +503,7 @@ impl<'a> Resolver<'a> {
|
|||
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
|
||||
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
||||
None => Err(Determinacy::determined(
|
||||
this.graph_root.unresolved_invocations.borrow().is_empty()
|
||||
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
||||
)),
|
||||
}
|
||||
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ impl<'a> Resolver<'a> {
|
|||
Err((Determined, Weak::No))
|
||||
} else if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
|
||||
Ok(binding)
|
||||
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
|
||||
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
|
||||
// Macro-expanded `extern crate` items can add names to extern prelude.
|
||||
Err((Undetermined, Weak::No))
|
||||
} else {
|
||||
|
|
@ -348,7 +348,7 @@ impl<'a> Resolver<'a> {
|
|||
// progress, we have to ignore those potential unresolved invocations from other modules
|
||||
// and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
|
||||
// shadowing is enabled, see `macro_expanded_macro_export_errors`).
|
||||
let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
|
||||
let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
|
||||
if let Some(binding) = resolution.binding {
|
||||
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
|
||||
return check_usable(self, binding);
|
||||
|
|
|
|||
|
|
@ -635,8 +635,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
});
|
||||
let default_needs_object_self = |param: &ty::GenericParamDef| {
|
||||
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
|
||||
if is_object && has_default {
|
||||
if tcx.at(span).type_of(param.def_id).has_self_ty() {
|
||||
if is_object && has_default && has_self {
|
||||
let self_param = tcx.types.self_param;
|
||||
if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) {
|
||||
// There is no suitable inference default for a type parameter
|
||||
// that references self, in an object type.
|
||||
return true;
|
||||
|
|
@ -2030,7 +2031,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// `Self` in trait or type alias.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
self.prohibit_generics(&path.segments);
|
||||
tcx.mk_self_type()
|
||||
tcx.types.self_param
|
||||
}
|
||||
Res::SelfTy(_, Some(def_id)) => {
|
||||
// `Self` in impl (we know the concrete type).
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let is_non_ref_pat = match pat.node {
|
||||
PatKind::Struct(..) |
|
||||
PatKind::TupleStruct(..) |
|
||||
PatKind::Or(_) |
|
||||
PatKind::Tuple(..) |
|
||||
PatKind::Box(_) |
|
||||
PatKind::Range(..) |
|
||||
|
|
@ -309,6 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Struct(ref qpath, ref fields, etc) => {
|
||||
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||
for pat in pats {
|
||||
self.check_pat_walk(pat, expected, def_bm, discrim_span);
|
||||
}
|
||||
expected_ty
|
||||
}
|
||||
PatKind::Tuple(ref elements, ddpos) => {
|
||||
let mut expected_len = elements.len();
|
||||
if ddpos.is_some() {
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ fn compare_self_type<'tcx>(
|
|||
let self_string = |method: &ty::AssocItem| {
|
||||
let untransformed_self_ty = match method.container {
|
||||
ty::ImplContainer(_) => impl_trait_ref.self_ty(),
|
||||
ty::TraitContainer(_) => tcx.mk_self_type()
|
||||
ty::TraitContainer(_) => tcx.types.self_param
|
||||
};
|
||||
let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ fn check_associated_item(
|
|||
let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id));
|
||||
|
||||
let (mut implied_bounds, self_ty) = match item.container {
|
||||
ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
|
||||
ty::TraitContainer(_) => (vec![], fcx.tcx.types.self_param),
|
||||
ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
|
||||
fcx.tcx.type_of(def_id))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -716,7 +716,7 @@ fn super_predicates_of(
|
|||
let icx = ItemCtxt::new(tcx, trait_def_id);
|
||||
|
||||
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
|
||||
let self_param_ty = tcx.mk_self_type();
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No,
|
||||
item.span);
|
||||
|
||||
|
|
@ -900,6 +900,20 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
|
|||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
Some(tcx.hir().local_def_id(parent_id))
|
||||
}
|
||||
// FIXME(#43408) enable this in all cases when we get lazy normalization.
|
||||
Node::AnonConst(&anon_const) => {
|
||||
// HACK(eddyb) this provides the correct generics when the workaround
|
||||
// for a const parameter `AnonConst` is being used elsewhere, as then
|
||||
// there won't be the kind of cyclic dependency blocking #43408.
|
||||
let expr = &tcx.hir().body(anon_const.body).value;
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
if AstConv::const_param_def_id(&icx, expr).is_some() {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
Some(tcx.hir().local_def_id(parent_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Node::Expr(&hir::Expr {
|
||||
node: hir::ExprKind::Closure(..),
|
||||
..
|
||||
|
|
@ -1014,13 +1028,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
|
|||
synthetic,
|
||||
..
|
||||
} => {
|
||||
if param.name.ident().name == kw::SelfUpper {
|
||||
span_bug!(
|
||||
param.span,
|
||||
"`Self` should not be the name of a regular parameter"
|
||||
);
|
||||
}
|
||||
|
||||
if !allow_defaults && default.is_some() {
|
||||
if !tcx.features().default_type_parameter_fallback {
|
||||
tcx.lint_hir(
|
||||
|
|
@ -1044,13 +1051,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
|
|||
}
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
if param.name.ident().name == kw::SelfUpper {
|
||||
span_bug!(
|
||||
param.span,
|
||||
"`Self` should not be the name of a regular parameter",
|
||||
);
|
||||
}
|
||||
|
||||
ty::GenericParamDefKind::Const
|
||||
}
|
||||
_ => return None,
|
||||
|
|
@ -1567,7 +1567,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
&format!(
|
||||
"defining opaque type use restricts opaque \
|
||||
type by using the generic parameter `{}` twice",
|
||||
p.name
|
||||
p,
|
||||
),
|
||||
);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
|
||||
use super::explicit::ExplicitPredicatesMap;
|
||||
|
|
@ -178,11 +177,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
// let _: () = substs.region_at(0);
|
||||
check_explicit_predicates(
|
||||
tcx,
|
||||
&def.did,
|
||||
def.did,
|
||||
substs,
|
||||
required_predicates,
|
||||
explicit_map,
|
||||
IgnoreSelfTy(false),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -208,11 +207,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
.substs;
|
||||
check_explicit_predicates(
|
||||
tcx,
|
||||
&ex_trait_ref.skip_binder().def_id,
|
||||
ex_trait_ref.skip_binder().def_id,
|
||||
substs,
|
||||
required_predicates,
|
||||
explicit_map,
|
||||
IgnoreSelfTy(true),
|
||||
Some(tcx.types.self_param),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -223,11 +222,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
debug!("Projection");
|
||||
check_explicit_predicates(
|
||||
tcx,
|
||||
&tcx.associated_item(obj.item_def_id).container.id(),
|
||||
tcx.associated_item(obj.item_def_id).container.id(),
|
||||
obj.substs,
|
||||
required_predicates,
|
||||
explicit_map,
|
||||
IgnoreSelfTy(false),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -236,9 +235,6 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IgnoreSelfTy(bool);
|
||||
|
||||
/// We also have to check the explicit predicates
|
||||
/// declared on the type.
|
||||
///
|
||||
|
|
@ -256,25 +252,25 @@ pub struct IgnoreSelfTy(bool);
|
|||
/// applying the substitution as above.
|
||||
pub fn check_explicit_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: &DefId,
|
||||
def_id: DefId,
|
||||
substs: &[Kind<'tcx>],
|
||||
required_predicates: &mut RequiredPredicates<'tcx>,
|
||||
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
|
||||
ignore_self_ty: IgnoreSelfTy,
|
||||
ignored_self_ty: Option<Ty<'tcx>>,
|
||||
) {
|
||||
debug!(
|
||||
"check_explicit_predicates(def_id={:?}, \
|
||||
substs={:?}, \
|
||||
explicit_map={:?}, \
|
||||
required_predicates={:?}, \
|
||||
ignore_self_ty={:?})",
|
||||
ignored_self_ty={:?})",
|
||||
def_id,
|
||||
substs,
|
||||
explicit_map,
|
||||
required_predicates,
|
||||
ignore_self_ty,
|
||||
ignored_self_ty,
|
||||
);
|
||||
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id);
|
||||
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
|
||||
|
||||
for outlives_predicate in explicit_predicates.iter() {
|
||||
debug!("outlives_predicate = {:?}", &outlives_predicate);
|
||||
|
|
@ -313,9 +309,9 @@ pub fn check_explicit_predicates<'tcx>(
|
|||
// = X` binding from the object type (there must be such a
|
||||
// binding) and thus infer an outlives requirement that `X:
|
||||
// 'b`.
|
||||
if ignore_self_ty.0 {
|
||||
if let Some(self_ty) = ignored_self_ty {
|
||||
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
|
||||
if ty.has_self_ty() {
|
||||
if ty.walk().any(|ty| ty == self_ty) {
|
||||
debug!("skipping self ty = {:?}", &ty);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2303,7 +2303,7 @@ impl Clean<Item> for ty::AssocItem {
|
|||
ty::ImplContainer(def_id) => {
|
||||
cx.tcx.type_of(def_id)
|
||||
}
|
||||
ty::TraitContainer(_) => cx.tcx.mk_self_type()
|
||||
ty::TraitContainer(_) => cx.tcx.types.self_param,
|
||||
};
|
||||
let self_arg_ty = *sig.input(0).skip_binder();
|
||||
if self_arg_ty == self_ty {
|
||||
|
|
@ -4107,6 +4107,9 @@ fn name_from_pat(p: &hir::Pat) -> String {
|
|||
if etc { ", .." } else { "" }
|
||||
)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
|
||||
}
|
||||
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
|
||||
.collect::<Vec<String>>().join(", ")),
|
||||
PatKind::Box(ref p) => name_from_pat(&**p),
|
||||
|
|
|
|||
|
|
@ -149,9 +149,11 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId,
|
|||
return true
|
||||
}
|
||||
let predicates = cx.tcx.super_predicates_of(child);
|
||||
debug_assert!(cx.tcx.generics_of(child).has_self);
|
||||
let self_ty = cx.tcx.types.self_param;
|
||||
predicates.predicates.iter().filter_map(|(pred, _)| {
|
||||
if let ty::Predicate::Trait(ref pred) = *pred {
|
||||
if pred.skip_binder().trait_ref.self_ty().is_self() {
|
||||
if pred.skip_binder().trait_ref.self_ty() == self_ty {
|
||||
Some(pred.def_id())
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ unwind = { path = "../libunwind" }
|
|||
hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.34"
|
||||
version = "0.3.35"
|
||||
default-features = false # don't use coresymbolication on OSX
|
||||
features = [
|
||||
"rustc-dep-of-std", # enable build support for integrating into libstd
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ impl Command {
|
|||
_f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
|
||||
) {
|
||||
// Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
|
||||
unimplemented!();;
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self, stdin: Stdio) {
|
||||
|
|
|
|||
|
|
@ -572,9 +572,10 @@ impl Pat {
|
|||
match &self.node {
|
||||
PatKind::Ident(_, _, Some(p)) => p.walk(it),
|
||||
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
|
||||
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
|
||||
s.iter().all(|p| p.walk(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, s)
|
||||
| PatKind::Tuple(s)
|
||||
| PatKind::Slice(s)
|
||||
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
|
||||
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
|
||||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
|
|
@ -648,6 +649,10 @@ pub enum PatKind {
|
|||
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
|
||||
TupleStruct(Path, Vec<P<Pat>>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
Or(Vec<P<Pat>>),
|
||||
|
||||
/// A possibly qualified path pattern.
|
||||
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
|
||||
/// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{self, Attribute, Name, PatKind};
|
||||
use crate::ast::{self, NodeId, Attribute, Name, PatKind};
|
||||
use crate::attr::{HasAttrs, Stability, Deprecation};
|
||||
use crate::source_map::SourceMap;
|
||||
use crate::edition::Edition;
|
||||
|
|
@ -671,13 +671,13 @@ bitflags::bitflags! {
|
|||
}
|
||||
|
||||
pub trait Resolver {
|
||||
fn next_node_id(&mut self) -> ast::NodeId;
|
||||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId;
|
||||
fn get_module_scope(&mut self, id: NodeId) -> ExpnId;
|
||||
|
||||
fn resolve_dollar_crates(&mut self);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
|
||||
derives: &[ExpnId]);
|
||||
extra_placeholders: &[NodeId]);
|
||||
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
|
||||
|
||||
fn resolve_imports(&mut self);
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
// Unresolved macros produce dummy outputs as a recovery measure.
|
||||
invocations.reverse();
|
||||
let mut expanded_fragments = Vec::new();
|
||||
let mut derives: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
|
||||
let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
|
||||
let mut undetermined_invocations = Vec::new();
|
||||
let (mut progress, mut force) = (false, !self.monotonic);
|
||||
loop {
|
||||
|
|
@ -347,13 +347,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
|
||||
let mut item = self.fully_configure(item);
|
||||
item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
|
||||
let derives = derives.entry(invoc.expansion_data.id).or_default();
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
|
||||
|
||||
derives.reserve(traits.len());
|
||||
derive_placeholders.reserve(traits.len());
|
||||
invocations.reserve(traits.len());
|
||||
for path in traits {
|
||||
let expn_id = ExpnId::fresh(None);
|
||||
derives.push(expn_id);
|
||||
derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
|
||||
invocations.push(Invocation {
|
||||
kind: InvocationKind::Derive { path, item: item.clone() },
|
||||
fragment_kind: invoc.fragment_kind,
|
||||
|
|
@ -365,7 +366,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
let fragment = invoc.fragment_kind
|
||||
.expect_from_annotatables(::std::iter::once(item));
|
||||
self.collect_invocations(fragment, derives)
|
||||
self.collect_invocations(fragment, derive_placeholders)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
|
@ -384,10 +385,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
// Finally incorporate all the expanded macros into the input AST fragment.
|
||||
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
|
||||
while let Some(expanded_fragments) = expanded_fragments.pop() {
|
||||
for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() {
|
||||
let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
|
||||
placeholder_expander.add(NodeId::placeholder_from_expn_id(mark),
|
||||
expanded_fragment, derives);
|
||||
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
|
||||
placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
|
||||
expanded_fragment, derive_placeholders);
|
||||
}
|
||||
}
|
||||
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
|
||||
|
|
@ -404,7 +406,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
/// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
|
||||
/// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
|
||||
/// prepares data for resolving paths of macro invocations.
|
||||
fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[ExpnId])
|
||||
fn collect_invocations(&mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId])
|
||||
-> (AstFragment, Vec<Invocation>) {
|
||||
// Resolve `$crate`s in the fragment for pretty-printing.
|
||||
self.cx.resolver.resolve_dollar_crates();
|
||||
|
|
@ -423,9 +425,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
collector.invocations
|
||||
};
|
||||
|
||||
// FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
|
||||
if self.monotonic {
|
||||
self.cx.resolver.visit_ast_fragment_with_placeholders(
|
||||
self.cx.current_expansion.id, &fragment, derives);
|
||||
self.cx.current_expansion.id, &fragment, extra_placeholders);
|
||||
}
|
||||
|
||||
(fragment, invocations)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use crate::ast::{self, NodeId};
|
|||
use crate::source_map::{DUMMY_SP, dummy_spanned};
|
||||
use crate::ext::base::ExtCtxt;
|
||||
use crate::ext::expand::{AstFragment, AstFragmentKind};
|
||||
use crate::ext::hygiene::ExpnId;
|
||||
use crate::tokenstream::TokenStream;
|
||||
use crate::mut_visit::*;
|
||||
use crate::ptr::P;
|
||||
|
|
@ -86,11 +85,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec<ExpnId>) {
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
|
||||
fragment.mut_visit_with(self);
|
||||
if let AstFragment::Items(mut items) = fragment {
|
||||
for derive in derives {
|
||||
match self.remove(NodeId::placeholder_from_expn_id(derive)) {
|
||||
for placeholder in placeholders {
|
||||
match self.remove(placeholder) {
|
||||
AstFragment::Items(derived_items) => items.extend(derived_items),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -559,6 +559,9 @@ declare_features! (
|
|||
// Allows `impl Trait` to be used inside type aliases (RFC 2515).
|
||||
(active, type_alias_impl_trait, "1.38.0", Some(63063), None),
|
||||
|
||||
// Allows the use of or-patterns, e.g. `0 | 1`.
|
||||
(active, or_patterns, "1.38.0", Some(54883), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
|
|||
sym::impl_trait_in_bindings,
|
||||
sym::generic_associated_types,
|
||||
sym::const_generics,
|
||||
sym::or_patterns,
|
||||
sym::let_chains,
|
||||
];
|
||||
|
||||
|
|
@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate,
|
|||
gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental");
|
||||
gate_all!(async_closure_spans, async_closure, "async closures are unstable");
|
||||
gate_all!(yield_spans, generators, "yield syntax is experimental");
|
||||
gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental");
|
||||
|
||||
let visitor = &mut PostExpansionVisitor {
|
||||
context: &ctx,
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
vis.visit_span(span);
|
||||
};
|
||||
}
|
||||
PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Box(inner) => vis.visit_pat(inner),
|
||||
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
|
||||
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
|
||||
|
|
@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
vis.visit_expr(e2);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Tuple(elems)
|
||||
| PatKind::Slice(elems)
|
||||
| PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Paren(inner) => vis.visit_pat(inner),
|
||||
PatKind::Mac(mac) => vis.visit_mac(mac),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ use syntax_pos::{BytePos, Pos, Span};
|
|||
use rustc_lexer::Base;
|
||||
use rustc_lexer::unescape;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::char;
|
||||
use std::iter;
|
||||
use std::convert::TryInto;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use log::debug;
|
||||
|
|
@ -181,18 +179,7 @@ impl<'a> StringReader<'a> {
|
|||
let string = self.str_from(start);
|
||||
// comments with only more "/"s are not doc comments
|
||||
let tok = if is_doc_comment(string) {
|
||||
let mut idx = 0;
|
||||
loop {
|
||||
idx = match string[idx..].find('\r') {
|
||||
None => break,
|
||||
Some(it) => idx + it + 1
|
||||
};
|
||||
if string[idx..].chars().next() != Some('\n') {
|
||||
self.err_span_(start + BytePos(idx as u32 - 1),
|
||||
start + BytePos(idx as u32),
|
||||
"bare CR not allowed in doc-comment");
|
||||
}
|
||||
}
|
||||
self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment");
|
||||
token::DocComment(Symbol::intern(string))
|
||||
} else {
|
||||
token::Comment
|
||||
|
|
@ -217,15 +204,10 @@ impl<'a> StringReader<'a> {
|
|||
}
|
||||
|
||||
let tok = if is_doc_comment {
|
||||
let has_cr = string.contains('\r');
|
||||
let string = if has_cr {
|
||||
self.translate_crlf(start,
|
||||
string,
|
||||
"bare CR not allowed in block doc-comment")
|
||||
} else {
|
||||
string.into()
|
||||
};
|
||||
token::DocComment(Symbol::intern(&string[..]))
|
||||
self.forbid_bare_cr(start,
|
||||
string,
|
||||
"bare CR not allowed in block doc-comment");
|
||||
token::DocComment(Symbol::intern(string))
|
||||
} else {
|
||||
token::Comment
|
||||
};
|
||||
|
|
@ -516,49 +498,16 @@ impl<'a> StringReader<'a> {
|
|||
&self.src[self.src_index(start)..self.src_index(end)]
|
||||
}
|
||||
|
||||
/// Converts CRLF to LF in the given string, raising an error on bare CR.
|
||||
fn translate_crlf<'b>(&self, start: BytePos, s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
|
||||
let mut chars = s.char_indices().peekable();
|
||||
while let Some((i, ch)) = chars.next() {
|
||||
if ch == '\r' {
|
||||
if let Some((lf_idx, '\n')) = chars.peek() {
|
||||
return translate_crlf_(self, start, s, *lf_idx, chars, errmsg).into();
|
||||
}
|
||||
let pos = start + BytePos(i as u32);
|
||||
let end_pos = start + BytePos((i + ch.len_utf8()) as u32);
|
||||
self.err_span_(pos, end_pos, errmsg);
|
||||
}
|
||||
}
|
||||
return s.into();
|
||||
|
||||
fn translate_crlf_(rdr: &StringReader<'_>,
|
||||
start: BytePos,
|
||||
s: &str,
|
||||
mut j: usize,
|
||||
mut chars: iter::Peekable<impl Iterator<Item = (usize, char)>>,
|
||||
errmsg: &str)
|
||||
-> String {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
// Skip first CR
|
||||
buf.push_str(&s[.. j - 1]);
|
||||
while let Some((i, ch)) = chars.next() {
|
||||
if ch == '\r' {
|
||||
if j < i {
|
||||
buf.push_str(&s[j..i]);
|
||||
}
|
||||
let next = i + ch.len_utf8();
|
||||
j = next;
|
||||
if chars.peek().map(|(_, ch)| *ch) != Some('\n') {
|
||||
let pos = start + BytePos(i as u32);
|
||||
let end_pos = start + BytePos(next as u32);
|
||||
rdr.err_span_(pos, end_pos, errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if j < s.len() {
|
||||
buf.push_str(&s[j..]);
|
||||
}
|
||||
buf
|
||||
fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) {
|
||||
let mut idx = 0;
|
||||
loop {
|
||||
idx = match s[idx..].find('\r') {
|
||||
None => break,
|
||||
Some(it) => idx + it + 1
|
||||
};
|
||||
self.err_span_(start + BytePos(idx as u32 - 1),
|
||||
start + BytePos(idx as u32),
|
||||
errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ pub struct ParseSess {
|
|||
// Places where `yield e?` exprs were used and should be feature gated.
|
||||
pub yield_spans: Lock<Vec<Span>>,
|
||||
pub injected_crate_name: Once<Symbol>,
|
||||
// Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated.
|
||||
pub or_pattern_spans: Lock<Vec<Span>>,
|
||||
}
|
||||
|
||||
impl ParseSess {
|
||||
|
|
@ -96,6 +98,7 @@ impl ParseSess {
|
|||
async_closure_spans: Lock::new(Vec::new()),
|
||||
yield_spans: Lock::new(Vec::new()),
|
||||
injected_crate_name: Once::new(),
|
||||
or_pattern_spans: Lock::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ use errors::{Applicability, DiagnosticBuilder};
|
|||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Parses a pattern.
|
||||
pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
|
||||
pub fn parse_pat(
|
||||
&mut self,
|
||||
expected: Option<&'static str>
|
||||
) -> PResult<'a, P<Pat>> {
|
||||
self.parse_pat_with_range_pat(true, expected)
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +100,34 @@ impl<'a> Parser<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`).
|
||||
fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
|
||||
// Parse the first pattern.
|
||||
let first_pat = self.parse_pat(expected)?;
|
||||
|
||||
// If the next token is not a `|`, this is not an or-pattern and
|
||||
// we should exit here.
|
||||
if !self.check(&token::BinOp(token::Or)) {
|
||||
return Ok(first_pat)
|
||||
}
|
||||
|
||||
let lo = first_pat.span;
|
||||
|
||||
let mut pats = vec![first_pat];
|
||||
|
||||
while self.eat(&token::BinOp(token::Or)) {
|
||||
pats.push(self.parse_pat_with_range_pat(
|
||||
true, expected
|
||||
)?);
|
||||
}
|
||||
|
||||
let or_pattern_span = lo.to(self.prev_span);
|
||||
|
||||
self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span);
|
||||
|
||||
Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
|
||||
}
|
||||
|
||||
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
||||
/// allowed).
|
||||
fn parse_pat_with_range_pat(
|
||||
|
|
@ -240,7 +271,9 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parse a tuple or parenthesis pattern.
|
||||
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
|
||||
p.parse_pat_with_or(None)
|
||||
})?;
|
||||
|
||||
// Here, `(pat,)` is a tuple pattern.
|
||||
// For backward compatibility, `(..)` is a tuple pattern as well.
|
||||
|
|
@ -483,7 +516,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?;
|
||||
Ok(PatKind::TupleStruct(path, fields))
|
||||
}
|
||||
|
||||
|
|
@ -627,7 +660,7 @@ impl<'a> Parser<'a> {
|
|||
// Parsing a pattern of the form "fieldname: pat"
|
||||
let fieldname = self.parse_field_name()?;
|
||||
self.bump();
|
||||
let pat = self.parse_pat(None)?;
|
||||
let pat = self.parse_pat_with_or(None)?;
|
||||
hi = pat.span;
|
||||
(pat, fieldname, false)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -436,18 +436,30 @@ pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefM
|
|||
fn print_ident(&mut self, ident: ast::Ident);
|
||||
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
|
||||
fn strsep<T, F>(&mut self, sep: &'static str, space_before: bool,
|
||||
b: Breaks, elts: &[T], mut op: F)
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.rbox(0, b);
|
||||
let mut first = true;
|
||||
for elt in elts {
|
||||
if first { first = false; } else { self.word_space(","); }
|
||||
op(self, elt);
|
||||
if let Some((first, rest)) = elts.split_first() {
|
||||
op(self, first);
|
||||
for elt in rest {
|
||||
if space_before {
|
||||
self.space();
|
||||
}
|
||||
self.word_space(sep);
|
||||
op(self, elt);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.strsep(",", false, b, elts, op)
|
||||
}
|
||||
|
||||
fn maybe_print_comment(&mut self, pos: BytePos) {
|
||||
while let Some(ref cmnt) = self.next_comment() {
|
||||
if cmnt.pos < pos {
|
||||
|
|
@ -2353,6 +2365,9 @@ impl<'a> State<'a> {
|
|||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
|
||||
}
|
||||
PatKind::Path(None, ref path) => {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
|
|
@ -2429,16 +2444,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_pats(&mut self, pats: &[P<ast::Pat>]) {
|
||||
let mut first = true;
|
||||
for p in pats {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
self.s.space();
|
||||
self.word_space("|");
|
||||
}
|
||||
self.print_pat(p);
|
||||
}
|
||||
self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
|
||||
}
|
||||
|
||||
fn print_arm(&mut self, arm: &ast::Arm) {
|
||||
|
|
|
|||
|
|
@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Tuple(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Box(ref subpattern) |
|
||||
PatKind::Ref(ref subpattern, _) |
|
||||
PatKind::Paren(ref subpattern) => {
|
||||
|
|
@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
visitor.visit_expr(upper_bound);
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest => {},
|
||||
PatKind::Slice(ref elems) => {
|
||||
PatKind::Tuple(ref elems)
|
||||
| PatKind::Slice(ref elems)
|
||||
| PatKind::Or(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Mac(ref mac) => visitor.visit_mac(mac),
|
||||
|
|
|
|||
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