Auto merge of #58016 - Centril:rollup, r=Centril
Rollup of 12 pull requests Successful merges: - #57008 (suggest `|` when `,` founds in invalid match value) - #57106 (Mark str::trim.* functions as #[must_use].) - #57920 (use `SOURCE_DATE_EPOCH` for man page time if set) - #57934 (Introduce into_raw_non_null on Rc and Arc) - #57971 (SGX target: improve panic & exit handling) - #57980 (Add the edition guide to the bookshelf) - #57984 (Improve bug message in check_ty) - #57999 (Add MOVBE x86 CPU feature) - #58000 (Fixes and cleanups) - #58005 (update docs for fix_start/end_matches) - #58007 (Don't panic when accessing enum variant ctor using `Self` in match) - #58008 (Pass correct arguments to places_conflict) Failed merges: r? @ghost
This commit is contained in:
commit
f40aaa6827
|
@ -23,7 +23,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
use crate::compile;
|
use crate::compile;
|
||||||
use crate::tool::{self, Tool};
|
use crate::tool::{self, Tool};
|
||||||
use crate::cache::{INTERNER, Interned};
|
use crate::cache::{INTERNER, Interned};
|
||||||
use time;
|
use time::{self, Timespec};
|
||||||
|
|
||||||
pub fn pkgname(builder: &Builder, component: &str) -> String {
|
pub fn pkgname(builder: &Builder, component: &str) -> String {
|
||||||
if component == "cargo" {
|
if component == "cargo" {
|
||||||
|
@ -528,7 +528,19 @@ impl Step for Rustc {
|
||||||
t!(fs::create_dir_all(image.join("share/man/man1")));
|
t!(fs::create_dir_all(image.join("share/man/man1")));
|
||||||
let man_src = builder.src.join("src/doc/man");
|
let man_src = builder.src.join("src/doc/man");
|
||||||
let man_dst = image.join("share/man/man1");
|
let man_dst = image.join("share/man/man1");
|
||||||
let month_year = t!(time::strftime("%B %Y", &time::now()));
|
|
||||||
|
// Reproducible builds: If SOURCE_DATE_EPOCH is set, use that as the time.
|
||||||
|
let time = env::var("SOURCE_DATE_EPOCH")
|
||||||
|
.map(|timestamp| {
|
||||||
|
let epoch = timestamp.parse().map_err(|err| {
|
||||||
|
format!("could not parse SOURCE_DATE_EPOCH: {}", err)
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
time::at(Timespec::new(epoch, 0))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|_| time::now());
|
||||||
|
|
||||||
|
let month_year = t!(time::strftime("%B %Y", &time));
|
||||||
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
|
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
|
||||||
// to hardlink, and we don't want to edit the source templates
|
// to hardlink, and we don't want to edit the source templates
|
||||||
for file_entry in builder.read_dir(&man_src) {
|
for file_entry in builder.read_dir(&man_src) {
|
||||||
|
|
|
@ -71,6 +71,10 @@ accomplishing various tasks.
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
## The Edition Guide
|
||||||
|
|
||||||
|
[The Edition Guide](edition-guide/index.html) describes the Rust editions.
|
||||||
|
|
||||||
## The Rustc Book
|
## The Rustc Book
|
||||||
|
|
||||||
[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`.
|
[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`.
|
||||||
|
|
|
@ -433,6 +433,27 @@ impl<T: ?Sized> Rc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Rc`, returning the wrapped pointer as `NonNull<T>`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(rc_into_raw_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::rc::Rc;
|
||||||
|
///
|
||||||
|
/// let x = Rc::new(10);
|
||||||
|
/// let ptr = Rc::into_raw_non_null(x);
|
||||||
|
/// let deref = unsafe { *ptr.as_ref() };
|
||||||
|
/// assert_eq!(deref, 10);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "rc_into_raw_non_null", issue = "47336")]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_raw_non_null(this: Self) -> NonNull<T> {
|
||||||
|
// safe because Rc guarantees its pointer is non-null
|
||||||
|
unsafe { NonNull::new_unchecked(Rc::into_raw(this) as *mut _) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||||
///
|
///
|
||||||
/// [weak]: struct.Weak.html
|
/// [weak]: struct.Weak.html
|
||||||
|
|
|
@ -413,6 +413,27 @@ impl<T: ?Sized> Arc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Arc`, returning the wrapped pointer as `NonNull<T>`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(rc_into_raw_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::sync::Arc;
|
||||||
|
///
|
||||||
|
/// let x = Arc::new(10);
|
||||||
|
/// let ptr = Arc::into_raw_non_null(x);
|
||||||
|
/// let deref = unsafe { *ptr.as_ref() };
|
||||||
|
/// assert_eq!(deref, 10);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "rc_into_raw_non_null", issue = "47336")]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_raw_non_null(this: Self) -> NonNull<T> {
|
||||||
|
// safe because Arc guarantees its pointer is non-null
|
||||||
|
unsafe { NonNull::new_unchecked(Arc::into_raw(this) as *mut _) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||||
///
|
///
|
||||||
/// [weak]: struct.Weak.html
|
/// [weak]: struct.Weak.html
|
||||||
|
|
|
@ -3489,6 +3489,8 @@ impl str {
|
||||||
///
|
///
|
||||||
/// assert_eq!("Hello\tworld", s.trim());
|
/// assert_eq!("Hello\tworld", s.trim());
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn trim(&self) -> &str {
|
pub fn trim(&self) -> &str {
|
||||||
self.trim_matches(|c: char| c.is_whitespace())
|
self.trim_matches(|c: char| c.is_whitespace())
|
||||||
|
@ -3524,6 +3526,8 @@ impl str {
|
||||||
/// let s = " עברית ";
|
/// let s = " עברית ";
|
||||||
/// assert!(Some('ע') == s.trim_start().chars().next());
|
/// assert!(Some('ע') == s.trim_start().chars().next());
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a new slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||||
pub fn trim_start(&self) -> &str {
|
pub fn trim_start(&self) -> &str {
|
||||||
self.trim_start_matches(|c: char| c.is_whitespace())
|
self.trim_start_matches(|c: char| c.is_whitespace())
|
||||||
|
@ -3559,6 +3563,8 @@ impl str {
|
||||||
/// let s = " עברית ";
|
/// let s = " עברית ";
|
||||||
/// assert!(Some('ת') == s.trim_end().chars().rev().next());
|
/// assert!(Some('ת') == s.trim_end().chars().rev().next());
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a new slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||||
pub fn trim_end(&self) -> &str {
|
pub fn trim_end(&self) -> &str {
|
||||||
self.trim_end_matches(|c: char| c.is_whitespace())
|
self.trim_end_matches(|c: char| c.is_whitespace())
|
||||||
|
@ -3661,6 +3667,8 @@ impl str {
|
||||||
/// ```
|
/// ```
|
||||||
/// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
|
/// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a new slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
|
pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
|
||||||
where P::Searcher: DoubleEndedSearcher<'a>
|
where P::Searcher: DoubleEndedSearcher<'a>
|
||||||
|
@ -3706,6 +3714,8 @@ impl str {
|
||||||
/// let x: &[_] = &['1', '2'];
|
/// let x: &[_] = &['1', '2'];
|
||||||
/// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12");
|
/// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12");
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a new slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||||
pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
|
pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
|
||||||
let mut i = self.len();
|
let mut i = self.len();
|
||||||
|
@ -3749,6 +3759,8 @@ impl str {
|
||||||
/// ```
|
/// ```
|
||||||
/// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo");
|
/// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo");
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use = "this returns the trimmed string as a new slice, \
|
||||||
|
without modifying the original"]
|
||||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||||
pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
|
pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
|
||||||
where P::Searcher: ReverseSearcher<'a>
|
where P::Searcher: ReverseSearcher<'a>
|
||||||
|
@ -3774,10 +3786,10 @@ impl str {
|
||||||
///
|
///
|
||||||
/// # Text directionality
|
/// # Text directionality
|
||||||
///
|
///
|
||||||
/// A string is a sequence of bytes. 'Left' in this context means the first
|
/// A string is a sequence of bytes. `start` in this context means the first
|
||||||
/// position of that byte string; for a language like Arabic or Hebrew
|
/// position of that byte string; for a left-to-right language like English or
|
||||||
/// which are 'right to left' rather than 'left to right', this will be
|
/// Russian, this will be left side; and for right-to-left languages like
|
||||||
/// the _right_ side, not the left.
|
/// like Arabic or Hebrew, this will be the right side.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -3806,10 +3818,10 @@ impl str {
|
||||||
///
|
///
|
||||||
/// # Text directionality
|
/// # Text directionality
|
||||||
///
|
///
|
||||||
/// A string is a sequence of bytes. 'Right' in this context means the last
|
/// A string is a sequence of bytes. `end` in this context means the last
|
||||||
/// position of that byte string; for a language like Arabic or Hebrew
|
/// position of that byte string; for a left-to-right language like English or
|
||||||
/// which are 'right to left' rather than 'left to right', this will be
|
/// Russian, this will be right side; and for right-to-left languages like
|
||||||
/// the _left_ side, not the right.
|
/// like Arabic or Hebrew, this will be the left side.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub struct RawConst<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
|
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
|
||||||
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
|
/// matches the LocalState optimizations for easy conversions between Value and ConstValue.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
|
||||||
pub enum ConstValue<'tcx> {
|
pub enum ConstValue<'tcx> {
|
||||||
/// Used only for types with layout::abi::Scalar ABI and ZSTs
|
/// Used only for types with layout::abi::Scalar ABI and ZSTs
|
||||||
|
|
|
@ -147,6 +147,7 @@ const X86_WHITELIST: &[(&str, Option<&str>)] = &[
|
||||||
("fxsr", None),
|
("fxsr", None),
|
||||||
("lzcnt", None),
|
("lzcnt", None),
|
||||||
("mmx", Some("mmx_target_feature")),
|
("mmx", Some("mmx_target_feature")),
|
||||||
|
("movbe", Some("movbe_target_feature")),
|
||||||
("pclmulqdq", None),
|
("pclmulqdq", None),
|
||||||
("popcnt", None),
|
("popcnt", None),
|
||||||
("rdrand", None),
|
("rdrand", None),
|
||||||
|
|
|
@ -215,8 +215,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
||||||
if places_conflict::places_conflict(
|
if places_conflict::places_conflict(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
self.mir,
|
self.mir,
|
||||||
place,
|
|
||||||
&borrow_data.borrowed_place,
|
&borrow_data.borrowed_place,
|
||||||
|
place,
|
||||||
places_conflict::PlaceConflictBias::NoOverlap,
|
places_conflict::PlaceConflictBias::NoOverlap,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
|
|
|
@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
|
||||||
/// The locals are stored as `Option<Value>`s.
|
/// The locals are stored as `Option<Value>`s.
|
||||||
/// `None` represents a local that is currently dead, while a live local
|
/// `None` represents a local that is currently dead, while a live local
|
||||||
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
|
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
|
||||||
pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
|
pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
|
||||||
pub local_layouts: IndexVec<mir::Local, Cell<Option<TyLayout<'tcx>>>>,
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Current position within the function
|
// Current position within the function
|
||||||
|
@ -106,7 +105,15 @@ pub enum StackPopCleanup {
|
||||||
None { cleanup: bool },
|
None { cleanup: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
// State of a local variable
|
/// State of a local variable including a memoized layout
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
|
||||||
|
pub state: LocalValue<Tag, Id>,
|
||||||
|
/// Don't modify if `Some`, this is only used to prevent computing the layout twice
|
||||||
|
pub layout: Cell<Option<TyLayout<'tcx>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State of a local variable
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum LocalValue<Tag=(), Id=AllocId> {
|
pub enum LocalValue<Tag=(), Id=AllocId> {
|
||||||
Dead,
|
Dead,
|
||||||
|
@ -117,16 +124,16 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
|
||||||
Live(Operand<Tag, Id>),
|
Live(Operand<Tag, Id>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, Tag> LocalValue<Tag> {
|
impl<'tcx, Tag> LocalState<'tcx, Tag> {
|
||||||
pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
|
pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
|
||||||
match self {
|
match self.state {
|
||||||
LocalValue::Dead => err!(DeadLocal),
|
LocalValue::Dead => err!(DeadLocal),
|
||||||
LocalValue::Live(ref val) => Ok(val),
|
LocalValue::Live(ref val) => Ok(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
|
pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
|
||||||
match self {
|
match self.state {
|
||||||
LocalValue::Dead => err!(DeadLocal),
|
LocalValue::Dead => err!(DeadLocal),
|
||||||
LocalValue::Live(ref mut val) => Ok(val),
|
LocalValue::Live(ref mut val) => Ok(val),
|
||||||
}
|
}
|
||||||
|
@ -310,17 +317,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
pub fn layout_of_local(
|
pub fn layout_of_local(
|
||||||
&self,
|
&self,
|
||||||
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||||
local: mir::Local
|
local: mir::Local,
|
||||||
|
layout: Option<TyLayout<'tcx>>,
|
||||||
) -> EvalResult<'tcx, TyLayout<'tcx>> {
|
) -> EvalResult<'tcx, TyLayout<'tcx>> {
|
||||||
let cell = &frame.local_layouts[local];
|
match frame.locals[local].layout.get() {
|
||||||
if cell.get().is_none() {
|
None => {
|
||||||
|
let layout = ::interpret::operand::from_known_layout(layout, || {
|
||||||
let local_ty = frame.mir.local_decls[local].ty;
|
let local_ty = frame.mir.local_decls[local].ty;
|
||||||
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
|
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
|
||||||
let layout = self.layout_of(local_ty)?;
|
self.layout_of(local_ty)
|
||||||
cell.set(Some(layout));
|
})?;
|
||||||
|
frame.locals[local].layout.set(Some(layout));
|
||||||
|
Ok(layout)
|
||||||
|
}
|
||||||
|
Some(layout) => Ok(layout),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cell.get().unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
|
pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
|
||||||
|
@ -454,7 +465,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
// empty local array, we fill it in below, after we are inside the stack frame and
|
// empty local array, we fill it in below, after we are inside the stack frame and
|
||||||
// all methods actually know about the frame
|
// all methods actually know about the frame
|
||||||
locals: IndexVec::new(),
|
locals: IndexVec::new(),
|
||||||
local_layouts: IndexVec::from_elem_n(Default::default(), mir.local_decls.len()),
|
|
||||||
span,
|
span,
|
||||||
instance,
|
instance,
|
||||||
stmt: 0,
|
stmt: 0,
|
||||||
|
@ -466,12 +476,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
// We put some marker immediate into the locals that we later want to initialize.
|
// We put some marker immediate into the locals that we later want to initialize.
|
||||||
// This can be anything except for LocalValue::Dead -- because *that* is the
|
// This can be anything except for LocalValue::Dead -- because *that* is the
|
||||||
// value we use for things that we know are initially dead.
|
// value we use for things that we know are initially dead.
|
||||||
let dummy =
|
let dummy = LocalState {
|
||||||
LocalValue::Live(Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)));
|
state: LocalValue::Live(Operand::Immediate(Immediate::Scalar(
|
||||||
|
ScalarMaybeUndef::Undef,
|
||||||
|
))),
|
||||||
|
layout: Cell::new(None),
|
||||||
|
};
|
||||||
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
|
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
|
||||||
// Return place is handled specially by the `eval_place` functions, and the
|
// Return place is handled specially by the `eval_place` functions, and the
|
||||||
// entry in `locals` should never be used. Make it dead, to be sure.
|
// entry in `locals` should never be used. Make it dead, to be sure.
|
||||||
locals[mir::RETURN_PLACE] = LocalValue::Dead;
|
locals[mir::RETURN_PLACE].state = LocalValue::Dead;
|
||||||
// Now mark those locals as dead that we do not want to initialize
|
// Now mark those locals as dead that we do not want to initialize
|
||||||
match self.tcx.describe_def(instance.def_id()) {
|
match self.tcx.describe_def(instance.def_id()) {
|
||||||
// statics and constants don't have `Storage*` statements, no need to look for them
|
// statics and constants don't have `Storage*` statements, no need to look for them
|
||||||
|
@ -484,7 +498,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StorageLive(local) |
|
StorageLive(local) |
|
||||||
StorageDead(local) => {
|
StorageDead(local) => {
|
||||||
locals[local] = LocalValue::Dead;
|
locals[local].state = LocalValue::Dead;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -494,11 +508,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
}
|
}
|
||||||
// Finally, properly initialize all those that still have the dummy value
|
// Finally, properly initialize all those that still have the dummy value
|
||||||
for (idx, local) in locals.iter_enumerated_mut() {
|
for (idx, local) in locals.iter_enumerated_mut() {
|
||||||
match *local {
|
match local.state {
|
||||||
LocalValue::Live(_) => {
|
LocalValue::Live(_) => {
|
||||||
// This needs to be peoperly initialized.
|
// This needs to be properly initialized.
|
||||||
let layout = self.layout_of_local(self.frame(), idx)?;
|
let ty = self.monomorphize(mir.local_decls[idx].ty)?;
|
||||||
*local = LocalValue::Live(self.uninit_operand(layout)?);
|
let layout = self.layout_of(ty)?;
|
||||||
|
local.state = LocalValue::Live(self.uninit_operand(layout)?);
|
||||||
|
local.layout = Cell::new(Some(layout));
|
||||||
}
|
}
|
||||||
LocalValue::Dead => {
|
LocalValue::Dead => {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
|
@ -543,7 +559,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
}
|
}
|
||||||
// Deallocate all locals that are backed by an allocation.
|
// Deallocate all locals that are backed by an allocation.
|
||||||
for local in frame.locals {
|
for local in frame.locals {
|
||||||
self.deallocate_local(local)?;
|
self.deallocate_local(local.state)?;
|
||||||
}
|
}
|
||||||
// Validate the return value. Do this after deallocating so that we catch dangling
|
// Validate the return value. Do this after deallocating so that we catch dangling
|
||||||
// references.
|
// references.
|
||||||
|
@ -591,10 +607,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
|
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
|
||||||
trace!("{:?} is now live", local);
|
trace!("{:?} is now live", local);
|
||||||
|
|
||||||
let layout = self.layout_of_local(self.frame(), local)?;
|
let layout = self.layout_of_local(self.frame(), local, None)?;
|
||||||
let init = LocalValue::Live(self.uninit_operand(layout)?);
|
let init = LocalValue::Live(self.uninit_operand(layout)?);
|
||||||
// StorageLive *always* kills the value that's currently stored
|
// StorageLive *always* kills the value that's currently stored
|
||||||
Ok(mem::replace(&mut self.frame_mut().locals[local], init))
|
Ok(mem::replace(&mut self.frame_mut().locals[local].state, init))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the old value of the local.
|
/// Returns the old value of the local.
|
||||||
|
@ -603,7 +619,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
||||||
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
|
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
|
||||||
trace!("{:?} is now dead", local);
|
trace!("{:?} is now dead", local);
|
||||||
|
|
||||||
mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
|
mem::replace(&mut self.frame_mut().locals[local].state, LocalValue::Dead)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn deallocate_local(
|
pub(super) fn deallocate_local(
|
||||||
|
|
|
@ -18,7 +18,7 @@ mod visitor;
|
||||||
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
||||||
|
|
||||||
pub use self::eval_context::{
|
pub use self::eval_context::{
|
||||||
EvalContext, Frame, StackPopCleanup, LocalValue,
|
EvalContext, Frame, StackPopCleanup, LocalState, LocalValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
|
pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
|
||||||
|
|
|
@ -227,7 +227,7 @@ impl<'tcx, Tag> OpTy<'tcx, Tag>
|
||||||
// Use the existing layout if given (but sanity check in debug mode),
|
// Use the existing layout if given (but sanity check in debug mode),
|
||||||
// or compute the layout.
|
// or compute the layout.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from_known_layout<'tcx>(
|
pub(super) fn from_known_layout<'tcx>(
|
||||||
layout: Option<TyLayout<'tcx>>,
|
layout: Option<TyLayout<'tcx>>,
|
||||||
compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>>
|
compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>>
|
||||||
) -> EvalResult<'tcx, TyLayout<'tcx>> {
|
) -> EvalResult<'tcx, TyLayout<'tcx>> {
|
||||||
|
@ -457,14 +457,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
|
/// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
|
||||||
fn access_local(
|
pub fn access_local(
|
||||||
&self,
|
&self,
|
||||||
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||||
local: mir::Local,
|
local: mir::Local,
|
||||||
|
layout: Option<TyLayout<'tcx>>,
|
||||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||||
assert_ne!(local, mir::RETURN_PLACE);
|
assert_ne!(local, mir::RETURN_PLACE);
|
||||||
let op = *frame.locals[local].access()?;
|
let op = *frame.locals[local].access()?;
|
||||||
let layout = self.layout_of_local(frame, local)?;
|
let layout = self.layout_of_local(frame, local, layout)?;
|
||||||
Ok(OpTy { op, layout })
|
Ok(OpTy { op, layout })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,14 +474,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
fn eval_place_to_op(
|
fn eval_place_to_op(
|
||||||
&self,
|
&self,
|
||||||
mir_place: &mir::Place<'tcx>,
|
mir_place: &mir::Place<'tcx>,
|
||||||
|
layout: Option<TyLayout<'tcx>>,
|
||||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||||
use rustc::mir::Place::*;
|
use rustc::mir::Place::*;
|
||||||
let op = match *mir_place {
|
let op = match *mir_place {
|
||||||
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
|
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
|
||||||
Local(local) => self.access_local(self.frame(), local)?,
|
Local(local) => self.access_local(self.frame(), local, layout)?,
|
||||||
|
|
||||||
Projection(ref proj) => {
|
Projection(ref proj) => {
|
||||||
let op = self.eval_place_to_op(&proj.base)?;
|
let op = self.eval_place_to_op(&proj.base, None)?;
|
||||||
self.operand_projection(op, &proj.elem)?
|
self.operand_projection(op, &proj.elem)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +506,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
// FIXME: do some more logic on `move` to invalidate the old location
|
// FIXME: do some more logic on `move` to invalidate the old location
|
||||||
Copy(ref place) |
|
Copy(ref place) |
|
||||||
Move(ref place) =>
|
Move(ref place) =>
|
||||||
self.eval_place_to_op(place)?,
|
self.eval_place_to_op(place, layout)?,
|
||||||
|
|
||||||
Constant(ref constant) => {
|
Constant(ref constant) => {
|
||||||
let layout = from_known_layout(layout, || {
|
let layout = from_known_layout(layout, || {
|
||||||
|
|
|
@ -624,7 +624,7 @@ where
|
||||||
// their layout on return.
|
// their layout on return.
|
||||||
PlaceTy {
|
PlaceTy {
|
||||||
place: *return_place,
|
place: *return_place,
|
||||||
layout: self.layout_of_local(self.frame(), mir::RETURN_PLACE)?,
|
layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
|
||||||
},
|
},
|
||||||
None => return err!(InvalidNullPointerUsage),
|
None => return err!(InvalidNullPointerUsage),
|
||||||
},
|
},
|
||||||
|
@ -633,7 +633,7 @@ where
|
||||||
frame: self.cur_frame(),
|
frame: self.cur_frame(),
|
||||||
local,
|
local,
|
||||||
},
|
},
|
||||||
layout: self.layout_of_local(self.frame(), local)?,
|
layout: self.layout_of_local(self.frame(), local, None)?,
|
||||||
},
|
},
|
||||||
|
|
||||||
Projection(ref proj) => {
|
Projection(ref proj) => {
|
||||||
|
@ -901,7 +901,7 @@ where
|
||||||
// We need the layout of the local. We can NOT use the layout we got,
|
// We need the layout of the local. We can NOT use the layout we got,
|
||||||
// that might e.g., be an inner field of a struct with `Scalar` layout,
|
// that might e.g., be an inner field of a struct with `Scalar` layout,
|
||||||
// that has different alignment than the outer field.
|
// that has different alignment than the outer field.
|
||||||
let local_layout = self.layout_of_local(&self.stack[frame], local)?;
|
let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
|
||||||
let ptr = self.allocate(local_layout, MemoryKind::Stack);
|
let ptr = self.allocate(local_layout, MemoryKind::Stack);
|
||||||
// We don't have to validate as we can assume the local
|
// We don't have to validate as we can assume the local
|
||||||
// was already valid for its type.
|
// was already valid for its type.
|
||||||
|
|
|
@ -23,8 +23,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
use syntax::source_map::Span;
|
use syntax::source_map::Span;
|
||||||
|
|
||||||
use super::eval_context::{LocalValue, StackPopCleanup};
|
use super::eval_context::{LocalState, StackPopCleanup};
|
||||||
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef};
|
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef, LocalValue};
|
||||||
use const_eval::CompileTimeInterpreter;
|
use const_eval::CompileTimeInterpreter;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -321,7 +321,6 @@ impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
|
||||||
return_to_block,
|
return_to_block,
|
||||||
return_place -> (return_place.as_ref().map(|r| &**r)),
|
return_place -> (return_place.as_ref().map(|r| &**r)),
|
||||||
locals,
|
locals,
|
||||||
local_layouts -> _,
|
|
||||||
block,
|
block,
|
||||||
stmt,
|
stmt,
|
||||||
extra,
|
extra,
|
||||||
|
@ -340,7 +339,6 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
|
||||||
return_to_block,
|
return_to_block,
|
||||||
return_place,
|
return_place,
|
||||||
locals,
|
locals,
|
||||||
local_layouts: _,
|
|
||||||
block,
|
block,
|
||||||
stmt,
|
stmt,
|
||||||
extra: _,
|
extra: _,
|
||||||
|
@ -358,6 +356,22 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
|
||||||
|
where Ctx: SnapshotContext<'a>,
|
||||||
|
{
|
||||||
|
type Item = LocalValue<(), AllocIdSnapshot<'a>>;
|
||||||
|
|
||||||
|
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
|
||||||
|
let LocalState { state, layout: _ } = self;
|
||||||
|
state.snapshot(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_stable_hash_for!(struct LocalState<'tcx> {
|
||||||
|
state,
|
||||||
|
layout -> _,
|
||||||
|
});
|
||||||
|
|
||||||
impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b>
|
impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b>
|
||||||
for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
|
for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
|
||||||
{
|
{
|
||||||
|
|
|
@ -309,7 +309,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
mir.spread_arg,
|
mir.spread_arg,
|
||||||
mir.args_iter()
|
mir.args_iter()
|
||||||
.map(|local|
|
.map(|local|
|
||||||
(local, self.layout_of_local(self.frame(), local).unwrap().ty)
|
(local, self.layout_of_local(self.frame(), local, None).unwrap().ty)
|
||||||
)
|
)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
@ -383,7 +383,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let callee_layout =
|
let callee_layout =
|
||||||
self.layout_of_local(self.frame(), mir::RETURN_PLACE)?;
|
self.layout_of_local(self.frame(), mir::RETURN_PLACE, None)?;
|
||||||
if !callee_layout.abi.is_uninhabited() {
|
if !callee_layout.abi.is_uninhabited() {
|
||||||
return err!(FunctionRetMismatch(
|
return err!(FunctionRetMismatch(
|
||||||
self.tcx.types.never, callee_layout.ty
|
self.tcx.types.never, callee_layout.ty
|
||||||
|
|
|
@ -784,7 +784,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
||||||
report_unexpected_variant_def(tcx, &def, pat.span, qpath);
|
report_unexpected_variant_def(tcx, &def, pat.span, qpath);
|
||||||
return tcx.types.err;
|
return tcx.types.err;
|
||||||
}
|
}
|
||||||
Def::VariantCtor(_, CtorKind::Fictive) => {
|
Def::VariantCtor(_, CtorKind::Fictive) |
|
||||||
|
Def::VariantCtor(_, CtorKind::Fn) => {
|
||||||
report_unexpected_variant_def(tcx, &def, pat.span, qpath);
|
report_unexpected_variant_def(tcx, &def, pat.span, qpath);
|
||||||
return tcx.types.err;
|
return tcx.types.err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1303,12 +1303,12 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Node::GenericParam(param) => match param.kind {
|
Node::GenericParam(param) => match ¶m.kind {
|
||||||
hir::GenericParamKind::Type {
|
hir::GenericParamKind::Type {
|
||||||
default: Some(ref ty),
|
default: Some(ref ty),
|
||||||
..
|
..
|
||||||
} => icx.to_ty(ty),
|
} => icx.to_ty(ty),
|
||||||
_ => bug!("unexpected non-type NodeGenericParam"),
|
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
|
||||||
},
|
},
|
||||||
|
|
||||||
x => {
|
x => {
|
||||||
|
@ -2205,6 +2205,7 @@ fn from_target_feature(
|
||||||
Some("wasm_target_feature") => rust_features.wasm_target_feature,
|
Some("wasm_target_feature") => rust_features.wasm_target_feature,
|
||||||
Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature,
|
Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature,
|
||||||
Some("adx_target_feature") => rust_features.adx_target_feature,
|
Some("adx_target_feature") => rust_features.adx_target_feature,
|
||||||
|
Some("movbe_target_feature") => rust_features.movbe_target_feature,
|
||||||
Some(name) => bug!("unknown target feature gate {}", name),
|
Some(name) => bug!("unknown target feature gate {}", name),
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,7 +66,7 @@ IMAGE_BASE:
|
||||||
globvar EH_FRM_HDR_SIZE 8
|
globvar EH_FRM_HDR_SIZE 8
|
||||||
|
|
||||||
.Lreentry_panic_msg:
|
.Lreentry_panic_msg:
|
||||||
.asciz "Re-entered panicked enclave!"
|
.asciz "Re-entered aborted enclave!"
|
||||||
.Lreentry_panic_msg_end:
|
.Lreentry_panic_msg_end:
|
||||||
|
|
||||||
.Lusercall_panic_msg:
|
.Lusercall_panic_msg:
|
||||||
|
@ -80,7 +80,7 @@ IMAGE_BASE:
|
||||||
.org .+48 /* reserved bits */
|
.org .+48 /* reserved bits */
|
||||||
|
|
||||||
.data
|
.data
|
||||||
.Lpanicked:
|
.Laborted:
|
||||||
.byte 0
|
.byte 0
|
||||||
|
|
||||||
/* TCS local storage section */
|
/* TCS local storage section */
|
||||||
|
@ -134,6 +134,9 @@ sgx_entry:
|
||||||
jz .Lskip_debug_init
|
jz .Lskip_debug_init
|
||||||
mov %r10,%gs:tcsls_debug_panic_buf_ptr
|
mov %r10,%gs:tcsls_debug_panic_buf_ptr
|
||||||
.Lskip_debug_init:
|
.Lskip_debug_init:
|
||||||
|
/* check for abort */
|
||||||
|
bt $0,.Laborted(%rip)
|
||||||
|
jc .Lreentry_panic
|
||||||
/* check if returning from usercall */
|
/* check if returning from usercall */
|
||||||
mov %gs:tcsls_last_rsp,%r11
|
mov %gs:tcsls_last_rsp,%r11
|
||||||
test %r11,%r11
|
test %r11,%r11
|
||||||
|
@ -164,9 +167,6 @@ sgx_entry:
|
||||||
mov %r14,%r8
|
mov %r14,%r8
|
||||||
mov %r15,%r9
|
mov %r15,%r9
|
||||||
.Lskip_init:
|
.Lskip_init:
|
||||||
/* check for panic */
|
|
||||||
bt $0,.Lpanicked(%rip)
|
|
||||||
jc .Lreentry_panic
|
|
||||||
/* call into main entry point */
|
/* call into main entry point */
|
||||||
load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
|
load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
|
||||||
call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
|
call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
|
||||||
|
@ -237,18 +237,18 @@ sgx_entry:
|
||||||
stmxcsr (%rsp)
|
stmxcsr (%rsp)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.global panic_exit
|
.global usercall_exit
|
||||||
panic_exit:
|
usercall_exit:
|
||||||
/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
|
/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
|
||||||
testb $0xff,DEBUG(%rip)
|
testb $0xff,DEBUG(%rip)
|
||||||
jz .Lskip_save_registers
|
jz .Lskip_save_registers
|
||||||
push_callee_saved_registers
|
push_callee_saved_registers
|
||||||
movq %rsp,%gs:tcsls_panic_last_rsp
|
movq %rsp,%gs:tcsls_panic_last_rsp
|
||||||
.Lskip_save_registers:
|
.Lskip_save_registers:
|
||||||
/* set panicked bit */
|
/* set aborted bit */
|
||||||
movb $1,.Lpanicked(%rip)
|
movb $1,.Laborted(%rip)
|
||||||
/* call usercall exit(true) */
|
/* call usercall exit(true) */
|
||||||
mov $1,%esi /* RSI = usercall() argument: panic = true */
|
/* NOP: mov %rsi,%rsi */ /* RSI = usercall() argument: panic */
|
||||||
xor %rdx,%rdx /* RDX cleared */
|
xor %rdx,%rdx /* RDX cleared */
|
||||||
movq $usercall_nr_exit,%rdi /* RDI = usercall exit */
|
movq $usercall_nr_exit,%rdi /* RDI = usercall exit */
|
||||||
jmp .Lexit
|
jmp .Lexit
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
|
use super::usercalls::alloc::UserRef;
|
||||||
|
use cmp;
|
||||||
use io::{self, Write};
|
use io::{self, Write};
|
||||||
use slice::from_raw_parts_mut;
|
use mem;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn take_debug_panic_buf_ptr() -> *mut u8;
|
fn take_debug_panic_buf_ptr() -> *mut u8;
|
||||||
static DEBUG: u8;
|
static DEBUG: u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SgxPanicOutput(Option<&'static mut [u8]>);
|
pub(crate) struct SgxPanicOutput(Option<&'static mut UserRef<[u8]>>);
|
||||||
|
|
||||||
|
fn empty_user_slice() -> &'static mut UserRef<[u8]> {
|
||||||
|
unsafe { UserRef::from_raw_parts_mut(1 as *mut u8, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
impl SgxPanicOutput {
|
impl SgxPanicOutput {
|
||||||
pub(crate) fn new() -> Option<Self> {
|
pub(crate) fn new() -> Option<Self> {
|
||||||
|
@ -17,32 +23,36 @@ impl SgxPanicOutput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&mut self) -> &mut &'static mut [u8] {
|
fn init(&mut self) -> &mut &'static mut UserRef<[u8]> {
|
||||||
self.0.get_or_insert_with(|| unsafe {
|
self.0.get_or_insert_with(|| unsafe {
|
||||||
let ptr = take_debug_panic_buf_ptr();
|
let ptr = take_debug_panic_buf_ptr();
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
&mut []
|
empty_user_slice()
|
||||||
} else {
|
} else {
|
||||||
from_raw_parts_mut(ptr, 1024)
|
UserRef::from_raw_parts_mut(ptr, 1024)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for SgxPanicOutput {
|
impl Write for SgxPanicOutput {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
|
||||||
self.init().write(buf)
|
let dst = mem::replace(self.init(), empty_user_slice());
|
||||||
|
let written = cmp::min(src.len(), dst.len());
|
||||||
|
dst[..written].copy_from_enclave(&src[..written]);
|
||||||
|
self.0 = Some(&mut dst[written..]);
|
||||||
|
Ok(written)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
self.init().flush()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn panic_msg(msg: &str) -> ! {
|
pub extern "C" fn panic_msg(msg: &str) -> ! {
|
||||||
let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
|
let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
|
||||||
unsafe { panic_exit(); }
|
unsafe { usercall_exit(true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" { pub fn panic_exit() -> !; }
|
extern "C" { pub fn usercall_exit(panic: bool) -> !; }
|
||||||
|
|
|
@ -119,7 +119,7 @@ pub unsafe fn launch_thread() -> IoResult<()> {
|
||||||
/// Usercall `exit`. See the ABI documentation for more information.
|
/// Usercall `exit`. See the ABI documentation for more information.
|
||||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
pub fn exit(panic: bool) -> ! {
|
pub fn exit(panic: bool) -> ! {
|
||||||
unsafe { raw::exit(panic) }
|
unsafe { super::panic::usercall_exit(panic) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Usercall `wait`. See the ABI documentation for more information.
|
/// Usercall `wait`. See the ABI documentation for more information.
|
||||||
|
|
|
@ -125,7 +125,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn abort_internal() -> ! {
|
pub unsafe fn abort_internal() -> ! {
|
||||||
abi::panic::panic_exit()
|
abi::panic::usercall_exit(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hashmap_random_keys() -> (u64, u64) {
|
pub fn hashmap_random_keys() -> (u64, u64) {
|
||||||
|
|
|
@ -394,6 +394,7 @@ declare_features! (
|
||||||
(active, wasm_target_feature, "1.30.0", Some(44839), None),
|
(active, wasm_target_feature, "1.30.0", Some(44839), None),
|
||||||
(active, adx_target_feature, "1.32.0", Some(44839), None),
|
(active, adx_target_feature, "1.32.0", Some(44839), None),
|
||||||
(active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
|
(active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
|
||||||
|
(active, movbe_target_feature, "1.34.0", Some(44839), None),
|
||||||
|
|
||||||
// Allows macro invocations on modules expressions and statements and
|
// Allows macro invocations on modules expressions and statements and
|
||||||
// procedural macros to expand to non-items.
|
// procedural macros to expand to non-items.
|
||||||
|
|
|
@ -4381,9 +4381,14 @@ impl<'a> Parser<'a> {
|
||||||
if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) {
|
if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
seq_span,
|
seq_span,
|
||||||
"try adding parentheses",
|
"try adding parentheses to match on a tuple..",
|
||||||
format!("({})", seq_snippet),
|
format!("({})", seq_snippet),
|
||||||
Applicability::MachineApplicable
|
Applicability::MachineApplicable
|
||||||
|
).span_suggestion(
|
||||||
|
seq_span,
|
||||||
|
"..or a vertical bar to match on multiple alternatives",
|
||||||
|
format!("{}", seq_snippet.replace(",", " |")),
|
||||||
|
Applicability::MachineApplicable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
|
|
@ -2,37 +2,85 @@ error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:38:17
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:38:17
|
||||||
|
|
|
|
||||||
LL | while let b1, b2, b3 = reading_frame.next().expect("there should be a start codon") {
|
LL | while let b1, b2, b3 = reading_frame.next().expect("there should be a start codon") {
|
||||||
| --^------- help: try adding parentheses: `(b1, b2, b3)`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | while let (b1, b2, b3) = reading_frame.next().expect("there should be a start codon") {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | while let b1 | b2 | b3 = reading_frame.next().expect("there should be a start codon") {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:49:14
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:49:14
|
||||||
|
|
|
|
||||||
LL | if let b1, b2, b3 = reading_frame.next().unwrap() {
|
LL | if let b1, b2, b3 = reading_frame.next().unwrap() {
|
||||||
| --^------- help: try adding parentheses: `(b1, b2, b3)`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | if let (b1, b2, b3) = reading_frame.next().unwrap() {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | if let b1 | b2 | b3 = reading_frame.next().unwrap() {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:59:28
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:59:28
|
||||||
|
|
|
|
||||||
LL | Nucleotide::Adenine, Nucleotide::Cytosine, _ => true
|
LL | Nucleotide::Adenine, Nucleotide::Cytosine, _ => true
|
||||||
| -------------------^------------------------ help: try adding parentheses: `(Nucleotide::Adenine, Nucleotide::Cytosine, _)`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | (Nucleotide::Adenine, Nucleotide::Cytosine, _) => true
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | Nucleotide::Adenine | Nucleotide::Cytosine | _ => true
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:67:10
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:67:10
|
||||||
|
|
|
|
||||||
LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) {
|
LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) {
|
||||||
| -^----------- help: try adding parentheses: `(x, _barr_body)`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | for (x, _barr_body) in women.iter().map(|woman| woman.allosomes.clone()) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | for x | _barr_body in women.iter().map(|woman| woman.allosomes.clone()) {
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10
|
||||||
|
|
|
|
||||||
LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) {
|
LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) {
|
||||||
| -^------------------- help: try adding parentheses: `(x, y @ Allosome::Y(_))`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | for (x, y @ Allosome::Y(_)) in men.iter().map(|man| man.allosomes.clone()) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | for x | y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14
|
--> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14
|
||||||
|
|
|
|
||||||
LL | let women, men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
|
LL | let women, men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
|
||||||
| -----^---- help: try adding parentheses: `(women, men)`
|
| ^
|
||||||
|
help: try adding parentheses to match on a tuple..
|
||||||
|
|
|
||||||
|
LL | let (women, men): (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
help: ..or a vertical bar to match on multiple alternatives
|
||||||
|
|
|
||||||
|
LL | let women | men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#![feature(type_alias_enum_variants)]
|
||||||
|
pub enum Enum {
|
||||||
|
A(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Enum {
|
||||||
|
fn foo(&self) -> () {
|
||||||
|
match self {
|
||||||
|
Self::A => (),
|
||||||
|
//~^ ERROR expected unit struct/variant or constant, found tuple variant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0533]: expected unit struct/variant or constant, found tuple variant `<Self>::A`
|
||||||
|
--> $DIR/issue-58006.rs:9:13
|
||||||
|
|
|
||||||
|
LL | Self::A => (),
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0533`.
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Test for ICE from issue 57989
|
||||||
|
|
||||||
|
#![feature(nll)]
|
||||||
|
|
||||||
|
fn f(x: &i32) {
|
||||||
|
let g = &x;
|
||||||
|
*x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference
|
||||||
|
//~| ERROR cannot assign to `*x` because it is borrowed
|
||||||
|
g;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,24 @@
|
||||||
|
error[E0594]: cannot assign to `*x` which is behind a `&` reference
|
||||||
|
--> $DIR/issue-57989.rs:7:5
|
||||||
|
|
|
||||||
|
LL | fn f(x: &i32) {
|
||||||
|
| ---- help: consider changing this to be a mutable reference: `&mut i32`
|
||||||
|
LL | let g = &x;
|
||||||
|
LL | *x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference
|
||||||
|
| ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
|
||||||
|
|
||||||
|
error[E0506]: cannot assign to `*x` because it is borrowed
|
||||||
|
--> $DIR/issue-57989.rs:7:5
|
||||||
|
|
|
||||||
|
LL | let g = &x;
|
||||||
|
| -- borrow of `*x` occurs here
|
||||||
|
LL | *x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference
|
||||||
|
| ^^^^^^ assignment to borrowed `*x` occurs here
|
||||||
|
LL | //~| ERROR cannot assign to `*x` because it is borrowed
|
||||||
|
LL | g;
|
||||||
|
| - borrow later used here
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0506, E0594.
|
||||||
|
For more information about an error, try `rustc --explain E0506`.
|
|
@ -22,6 +22,7 @@
|
||||||
// gate-test-wasm_target_feature
|
// gate-test-wasm_target_feature
|
||||||
// gate-test-adx_target_feature
|
// gate-test-adx_target_feature
|
||||||
// gate-test-cmpxchg16b_target_feature
|
// gate-test-cmpxchg16b_target_feature
|
||||||
|
// gate-test-movbe_target_feature
|
||||||
// min-llvm-version 6.0
|
// min-llvm-version 6.0
|
||||||
|
|
||||||
#[target_feature(enable = "avx512bw")]
|
#[target_feature(enable = "avx512bw")]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839)
|
error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839)
|
||||||
--> $DIR/target-feature-gate.rs:27:18
|
--> $DIR/target-feature-gate.rs:28:18
|
||||||
|
|
|
|
||||||
LL | #[target_feature(enable = "avx512bw")]
|
LL | #[target_feature(enable = "avx512bw")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
Loading…
Reference in New Issue